New service grid for M-Cord
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..40b878d
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+node_modules/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 61b07cd..4ec3dcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
 profile
 *.moved-aside
 .idea
-xos.iml
 xos/configurations/frontend/Dockerfile
 xos/core/xoslib/karma-*
 xos/core/xoslib/docs
@@ -12,4 +11,5 @@
 node_modules
 xos/xos_configuration/*
 .idea/*
-xos.iml
+*.iml
+npm-debug.log
diff --git a/views/ngXosLib/README.md b/views/ngXosLib/README.md
new file mode 100644
index 0000000..0166efd
--- /dev/null
+++ b/views/ngXosLib/README.md
@@ -0,0 +1,101 @@
+# ngXosLib
+
+This is a collection of helpers to develop views as Angular SPA.
+
+## Tools
+
+This tools are designed to help you developing UI for XOS. As they born for this purpose if often necessary that a XOS instance is running on your sistem and responding at: `localhost:9999`. The `xos/configurations/frontend` is normally enough.
+
+### Apigen
+
+Usage: `npm run apigen`
+
+This tool will automatically generate an angular resource file for each endpoint available in Swagger.
+
+>You can generate api related documentation with: `npm run apidoc`. The output is locate in `api/docs`. You can have a list of available method also trough Swagger at `http://localhost:9999/docs/`
+
+### Vendors
+
+Xos comes with a preset of common libraries, as listed in `bower.json`:
+- angular
+- angular-route
+- angular-resource
+- angular-cookie
+- ng-lodash
+
+This libraries are server through Django, so they will not be included in your minified vendor file. To add a library and generate a new file (that will override the old one), you should:
+- enter `ngXosLib` folder
+- run `bower install [myPackage] --save`
+- rebuild the file with `gulp vendor`
+
+>_NOTE before adding libraries please discuss it to avoid this file to became huge_
+
+### Helpers
+
+XOS comes with an helper library that is automatically loaded in the Django template.
+
+To use it, add `xos.helpers` to your required modules:
+
+```
+angular.module('xos.myView', [
+  'xos.helpers'
+])
+```
+
+It will automatically ad a `token` to all your request, eventually you can take advantage of some other services:
+
+- **NoHyperlinks Interceptor**: will add a `?no_hyperlinks=1` to your request, to tell Django to return ids instead of links.
+- **XosApi** wrapper for `/xos` endpoints.
+- **XoslibApi** wrapper for `/xoslib` endpoints.
+- **HpcApi** wrapper for `/hpcapi` endpoints.
+
+>_NOTE: for the API related service, check documentation in [Apigen](#apigen) section._
+
+### Yo Xos
+
+We have created a [yeoman](http://yeoman.io/) generator to help you scaffolding views.
+
+>As it is in an early stage of development you should manually link it to your system, to do this enter `xos/core/xoslib/ngXosLib/generator-xos` and run `npm link`.
+
+#### To generate a new view
+
+From `xos/core/xoslib` run `yo xos`. This command will create a new folder with the provided name in: `xos/core/xoslib/ngXosViews` that contain your application.
+
+>If you left empty the view name it should be `xos/core/xoslib/ngXosViews/sampleView`
+
+#### Run a development server
+
+In your `view` folder and run `npm start`.
+
+_This will install required dependencies and start a local server with [BrowserSync](http://www.browsersync.io/)_
+
+#### Publish your view
+
+Once your view is done, from your view root folder, run: `npm run build`.
+
+This will build your application and copy files in the appropriate locations to be used by django.
+
+At this point you can enter: `http://localhost:9999/admin/core/dashboardview/add/` and add your custom view.
+
+>_NOTE url field should be `template:xosSampleView`_
+
+#### Install dependencies in your app
+
+To install a local dependency use bower with `--save`. Common modules are saved in `devDependencies` as they already loaded in the Django template.
+
+The `npm start` command is watching your dependencies and will automatically inject it in your `index.html`.
+
+#### Linting
+
+A styleguide is enforced trough [EsLint](http://eslint.org/) and is checked during the build process. We **highly** suggest to install the linter in your editor to have realtime hint.
+
+#### Test
+
+The generator set up a test environment with a default test.
+To run it execute: `npm test`
+
+## TODO
+
+- Use Angular $resource instead of $http
+- Use ngDoc instead of jsDoc
+- Define styleguide (both visual and js) and if needed define some UI components
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js b/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js
index 025813c..283e90d 100644
--- a/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js
+++ b/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js
@@ -1,18 +1,18 @@
 (function() {
-  'use strict';
+    'use strict';
 
-  angular
-    .module('xos.helpers')
-    .factory('SetCSRFToken', setCSRFToken);
+    angular
+        .module('xos.helpers')
+        .factory('SetCSRFToken', setCSRFToken);
 
-  function setCSRFToken($cookies) {
-    return {
-      request: function(request){
-        if(request.method !== 'GET'){
-          request.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
+    function setCSRFToken($cookies) {
+      return {
+        request: function(request){
+          if(request.method !== 'GET'){
+            request.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
+          }
+          return request;
         }
-        return request;
-      }
-    };
-  }
+      };
+    }
 })();
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index 25600aa..d5b53da 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -3,7 +3,12 @@
 
     angular.module('bugSnag', []).factory('$exceptionHandler', function () {
       return function (exception, cause) {
-        Bugsnag.notifyException(exception, {diagnostics:{cause: cause}});
+        if( window.Bugsnag ){
+          Bugsnag.notifyException(exception, {diagnostics:{cause: cause}});
+        }
+        else{
+          console.error(exception, cause, exception.stack);
+        }
       };
     });
 
diff --git a/views/ngXosViews/.gitignore b/views/ngXosViews/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/.gitignore
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/main.js b/views/ngXosViews/ceilometerDashboard/src/js/main.js
index 0bf12db..12f5e72 100644
--- a/views/ngXosViews/ceilometerDashboard/src/js/main.js
+++ b/views/ngXosViews/ceilometerDashboard/src/js/main.js
@@ -110,7 +110,7 @@
       // this open the accordion
       this.accordion = {
         open: {}
-      }
+      };
 
       /**
       * Open the active panel base on the service stored values
@@ -350,6 +350,7 @@
     }
   }
 })
+  // NOTE reading this on demand for a single
 .directive('ceilometerStats', function(){
   return {
     restrict: 'E',
diff --git a/views/ngXosViews/diagnostic/.bowerrc b/views/ngXosViews/diagnostic/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/.eslintrc b/views/ngXosViews/diagnostic/.eslintrc
new file mode 100644
index 0000000..ef5b468
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.eslintrc
@@ -0,0 +1,44 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "no-undef": 2,
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true,
+        "d3": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/.gitignore b/views/ngXosViews/diagnostic/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/bower.json b/views/ngXosViews/diagnostic/bower.json
new file mode 100644
index 0000000..edf419d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-serviceTopology",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The serviceTopology view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "d3": "~3.5.13",
+    "lodash": "~4.0.0",
+    "angular-animate": "~1.4.9"
+  },
+  "devDependencies": {
+    "jquery": "~2.1.4",
+    "angular-mocks": "~1.4.7",
+    "angular": "~1.4.7",
+    "angular-ui-router": "~0.2.15",
+    "angular-cookies": "~1.4.7",
+    "angular-resource": "~1.4.7",
+    "ng-lodash": "~0.3.0",
+    "bootstrap-css": "~3.3.6"
+  }
+}
diff --git a/views/ngXosViews/diagnostic/env/default.js b/views/ngXosViews/diagnostic/env/default.js
new file mode 100644
index 0000000..e9ed236
--- /dev/null
+++ b/views/ngXosViews/diagnostic/env/default.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://clnode067.clemson.cloudlab.us:9999/',
+  xoscsrftoken: 'ZhPiXOVgQH2S0QQtLTkx3DaESR7IOvQc',
+  xossessionid: '49cjbceeg483ife9rocex8h1st360ii3'
+};
diff --git a/views/ngXosViews/diagnostic/env/local.js b/views/ngXosViews/diagnostic/env/local.js
new file mode 100644
index 0000000..77f9585
--- /dev/null
+++ b/views/ngXosViews/diagnostic/env/local.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://xos.local:9999/',
+  xoscsrftoken: 'LNTm83Yqbabh0r60IZIl6rMYPHaYJdl1',
+  xossessionid: 'j9oazvejbv5jaiahmuhkba7f09ks8yuo'
+};
diff --git a/views/ngXosViews/diagnostic/env/mock.js b/views/ngXosViews/diagnostic/env/mock.js
new file mode 100644
index 0000000..c65eb2f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/env/mock.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://localhost:4000/',
+  xoscsrftoken: 'IGSrPSAOmBorK8uxbbscQbn3ODPb9dDW',
+  xossessionid: 'i8hltbdt3po3uxkbvfmzy15o98p9s157'
+};
diff --git a/views/ngXosViews/diagnostic/env/onlab_pod.js b/views/ngXosViews/diagnostic/env/onlab_pod.js
new file mode 100644
index 0000000..413bd04
--- /dev/null
+++ b/views/ngXosViews/diagnostic/env/onlab_pod.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://10.90.0.132/',
+  xoscsrftoken: 'bDZaZNRDU6BwUanvjfcGfKJHohG3mlqb',
+  xossessionid: '3nww58wgrlscs7boy2xzw11tji8ywal5'
+};
diff --git a/views/ngXosViews/diagnostic/gulp/build.js b/views/ngXosViews/diagnostic/gulp/build.js
new file mode 100644
index 0000000..cf2b40e
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulp/build.js
@@ -0,0 +1,151 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+var TEMPLATE_FOOTER = `
+angular.module('xos.diagnostic').run(function($location){
+  $location.path('/')
+});
+angular.bootstrap(angular.element('#xosDiagnostic'), ['xos.diagnostic']);`;
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [options.dashboards + 'xosDiagnostic.html'],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+    console.log(options.css);
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  gulp.task('copyCss', ['css'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosDiagnostic.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js',
+      options.tmp + 'templates.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosDiagnostic.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    // .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.diagnostic',
+        root: 'templates/',
+        // templateFooter: TEMPLATE_FOOTER
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', ['clean'], function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n.*)*\n<!-- endbower --><!-- endcss -->/, ''))
+      .pipe(replace(/<!-- bower:js -->(\n.*)*\n<!-- endbower --><!-- endjs -->/, ''))
+      .pipe(replace(/ng-app=".*"\s/, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosDiagnosticVendor.js',
+            options.static + 'js/xosDiagnostic.js',
+            options.static + 'css/xosDiagnostic.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosDiagnostic.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosDiagnosticVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'copyHtml',
+      'copyCss'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/gulp/server.js b/views/ngXosViews/diagnostic/gulp/server.js
new file mode 100644
index 0000000..7605294
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulp/server.js
@@ -0,0 +1,146 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+
+const environment = process.env.NODE_ENV;
+
+if (environment){
+  var conf = require(`../env/${environment}.js`);
+}
+else{
+  var conf = require('../env/default.js')
+}
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host || 'http://0.0.0.0:9999'
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  // open in browser with sync and proxy to 0.0.0.0
+  gulp.task('browser', function() {
+    browserSync.init({
+      // reloadDelay: 500,
+      // logLevel: 'debug',
+      // logConnections: true,
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/api': options.api,
+          '/xosHelpers/src': options.helpers
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/xos/') !== -1 ||
+            req.url.indexOf('/xoslib/') !== -1 ||
+            req.url.indexOf('/hpcapi/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.api + '*.js',
+            options.helpers + '**/*.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src(options.src + 'css/*.css'),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/diagnostic/gulpfile.js b/views/ngXosViews/diagnostic/gulpfile.js
new file mode 100644
index 0000000..7bdc6e0
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulpfile.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../ngXosLib/xosHelpers/src/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder from dev environment
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/diagnostic/karma.conf.js b/views/ngXosViews/diagnostic/karma.conf.js
new file mode 100644
index 0000000..5e312fa
--- /dev/null
+++ b/views/ngXosViews/diagnostic/karma.conf.js
@@ -0,0 +1,90 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      '../../../xos/core/xoslib/static/js/xosApi.js',
+      'src/js/main.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/diagnostic/mocks/data/instances.json b/views/ngXosViews/diagnostic/mocks/data/instances.json
new file mode 100644
index 0000000..d9814f3
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/instances.json
@@ -0,0 +1,322 @@
+[
+    {
+        "humanReadableName": "sflow_service_instance", 
+        "id": 8, 
+        "created": "2016-02-17T22:01:02.663Z", 
+        "updated": "2016-02-17T22:05:58.270Z", 
+        "enacted": "2016-02-17T22:05:58.281Z", 
+        "policed": "2016-02-17T22:05:59.137Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746758.281283, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000005", 
+        "instance_uuid": "42b75cb7-7205-4a68-9100-b2c1e3ea69b5", 
+        "name": "sflow_service_instance", 
+        "instance_name": "mysite_sflow-8", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 8, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            21, 
+            20
+        ]
+    }, 
+    {
+        "humanReadableName": "client1", 
+        "id": 4, 
+        "created": "2016-02-17T22:00:58.284Z", 
+        "updated": "2016-02-17T22:03:56.863Z", 
+        "enacted": "2016-02-17T22:03:56.872Z", 
+        "policed": "2016-02-17T22:03:56.953Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746636.872524, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000001", 
+        "instance_uuid": "cca264bb-8136-45dd-a5a3-41902a4bcf5b", 
+        "name": "client1", 
+        "instance_name": "mysite_clients-4", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 3, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            10, 
+            4, 
+            11
+        ]
+    }, 
+    {
+        "humanReadableName": "mysite_ceilometer-7", 
+        "id": 7, 
+        "created": "2016-02-17T22:01:02.550Z", 
+        "updated": "2016-02-17T22:06:15.667Z", 
+        "enacted": "2016-02-17T22:06:15.672Z", 
+        "policed": "2016-02-17T22:06:15.818Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746775.672678, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000006", 
+        "instance_uuid": "23d04870-5e0d-4b03-b2e2-032cbfec56fa", 
+        "name": "mysite_ceilometer", 
+        "instance_name": "mysite_ceilometer-7", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 7, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            18, 
+            19, 
+            5
+        ]
+    }, 
+    {
+        "humanReadableName": "onos_app_1", 
+        "id": 3, 
+        "created": "2016-02-17T22:00:58.258Z", 
+        "updated": "2016-02-17T22:04:43.301Z", 
+        "enacted": "2016-02-17T22:04:43.309Z", 
+        "policed": "2016-02-17T22:04:43.943Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746683.309321, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000002", 
+        "instance_uuid": "c21dc52f-363e-47f6-9a2a-489c0af392fb", 
+        "name": "onos_app_1", 
+        "instance_name": "mysite_onos_vbng-3", 
+        "ip": "130.127.133.59", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 5, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            15, 
+            14
+        ]
+    }, 
+    {
+        "humanReadableName": "ovs_vbng", 
+        "id": 6, 
+        "created": "2016-02-17T22:00:58.567Z", 
+        "updated": "2016-02-17T22:06:33.495Z", 
+        "enacted": "2016-02-17T22:06:33.562Z", 
+        "policed": "2016-02-17T22:06:34.619Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746793.562678, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000007", 
+        "instance_uuid": "81dc0638-c9bc-4396-be17-ea805050e388", 
+        "name": "ovs_vbng", 
+        "instance_name": "mysite_vbng-6", 
+        "ip": "130.127.133.59", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 2, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            8, 
+            3, 
+            9
+        ]
+    }, 
+    {
+        "humanReadableName": "onos_app_2", 
+        "id": 2, 
+        "created": "2016-02-17T22:00:58.199Z", 
+        "updated": "2016-02-17T22:05:26.512Z", 
+        "enacted": "2016-02-17T22:05:26.521Z", 
+        "policed": "2016-02-17T22:05:26.730Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746726.521625, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000003", 
+        "instance_uuid": "8e3f00c5-0957-4505-ae69-e03e41306435", 
+        "name": "onos_app_2", 
+        "instance_name": "mysite_onos_volt-2", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 4, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            12, 
+            13
+        ]
+    }, 
+    {
+        "humanReadableName": "ovs_volt", 
+        "id": 5, 
+        "created": "2016-02-17T22:00:58.540Z", 
+        "updated": "2016-02-17T22:06:50.666Z", 
+        "enacted": "2016-02-17T22:06:50.680Z", 
+        "policed": "2016-02-17T22:06:51.342Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746810.680553, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000008", 
+        "instance_uuid": "49c08f77-f05a-4c9b-859c-20c2982b19c6", 
+        "name": "ovs_volt", 
+        "instance_name": "mysite_volt-5", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 6, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            17, 
+            16, 
+            4
+        ]
+    }, 
+    {
+        "humanReadableName": "mysite_vsg-1", 
+        "id": 1, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-1", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    },
+    {
+        "humanReadableName": "mysite_vsg-2", 
+        "id": 11, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-2", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    },
+    {
+        "humanReadableName": "mysite_vsg-3", 
+        "id": 12, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "2 - Error", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-3", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json b/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json
new file mode 100644
index 0000000..8678222
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json
@@ -0,0 +1,242 @@
+[
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Existence of vcpe instance", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe", 
+        "unit": "vcpe", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of entries in DNS cache", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.cache.size", 
+        "unit": "entries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 150.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Unexpired entries that were thrown out of cache", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.replaced_unexpired_entries", 
+        "unit": "entries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of cache hits", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.queries_answered_locally", 
+        "unit": "queries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of cache misses", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.queries_forwarded", 
+        "unit": "queries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Volume of RAM", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "memory", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 2099.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Volume of RAM used", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "memory.usage", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 31.1625, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Average CPU utilization", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "cpu_util", 
+        "unit": "%", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.845000000000001, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    },
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.00030304561114446413, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.714042840024997e-06, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    },
+     {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.00030304561114446413, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.714042840024997e-06, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }
+]
diff --git a/views/ngXosViews/diagnostic/mocks/data/nodes.json b/views/ngXosViews/diagnostic/mocks/data/nodes.json
new file mode 100644
index 0000000..03ca1da
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/nodes.json
@@ -0,0 +1,53 @@
+[
+    {
+        "humanReadableName": "cp-3.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 3, 
+        "created": "2016-02-17T22:00:53.717Z", 
+        "updated": "2016-02-17T22:01:24.890Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-3.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }, 
+    {
+        "humanReadableName": "cp-2.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 2, 
+        "created": "2016-02-17T22:00:53.701Z", 
+        "updated": "2016-02-17T22:01:24.891Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-2.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }, 
+    {
+        "humanReadableName": "cp-1.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 1, 
+        "created": "2016-02-17T22:00:53.680Z", 
+        "updated": "2016-02-17T22:01:24.892Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-1.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/services.json b/views/ngXosViews/diagnostic/mocks/data/services.json
new file mode 100644
index 0000000..b3ae7b7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/services.json
@@ -0,0 +1,177 @@
+[
+   {
+      "humanReadableName":"service_vbng",
+      "id":1,
+      "created":"2016-02-17T19:36:04.242Z",
+      "updated":"2016-02-17T19:36:04.242Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vBNG",
+      "name":"service_vbng",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/vbngservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":null
+   },
+   {
+      "humanReadableName":"service_vsg",
+      "id":2,
+      "created":"2016-02-17T19:36:04.249Z",
+      "updated":"2016-02-17T19:36:04.249Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vCPE",
+      "name":"service_vsg",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/vsgservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"backend_network_label\": \"hpc_client\"}"
+   },
+   {
+      "humanReadableName":"service_volt",
+      "id":3,
+      "created":"2016-02-17T19:36:04.585Z",
+      "updated":"2016-02-17T19:36:04.585Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vOLT",
+      "name":"service_volt",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/voltservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":null
+   },
+   {
+      "humanReadableName":"service_ceilometer",
+      "id":6,
+      "created":"2016-02-17T19:36:09.291Z",
+      "updated":"2016-02-17T19:36:09.291Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"ceilometer",
+      "name":"service_ceilometer",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/ceilometer/ceilometerservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"ceilometer_pub_sub_url\": \"http://10.11.10.1:4455/\"}"
+   },
+   {
+      "humanReadableName":"service_sflow",
+      "id":7,
+      "created":"2016-02-17T19:36:09.339Z",
+      "updated":"2016-02-17T20:01:35.518Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768095.518195, \"last_failure\": 1455739295.518198, \"last_success\": 1455737795.306011, \"exponent\": 293, \"failures\": 293}",
+      "backend_status":"2 - Exception('defer object service_sflow due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"sflow",
+      "name":"service_sflow",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/ceilometer/sflowservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"sflow_api_port\": 33333, \"sflow_port\": 6343}"
+   },
+   {
+      "humanReadableName":"service_ONOS_vOLT",
+      "id":4,
+      "created":"2016-02-17T19:36:04.840Z",
+      "updated":"2016-02-17T20:01:35.987Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768095.987071, \"failures\": 282, \"last_success\": 1455737792.664808, \"exponent\": 282, \"last_failure\": 1455739295.987074}",
+      "backend_status":"2 - Exception('defer object service_ONOS_vOLT due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"onos",
+      "name":"service_ONOS_vOLT",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/onos/onosservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"no_container\": false}"
+   },
+   {
+      "humanReadableName":"service_ONOS_vBNG",
+      "id":5,
+      "created":"2016-02-17T19:36:04.917Z",
+      "updated":"2016-02-17T20:01:36.011Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768096.011113, \"failures\": 282, \"last_success\": 1455737792.697535, \"exponent\": 282, \"last_failure\": 1455739296.011116}",
+      "backend_status":"2 - Exception('defer object service_ONOS_vBNG due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"onos",
+      "name":"service_ONOS_vBNG",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/onos/onosservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"no_container\": false}"
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/subscribers.json b/views/ngXosViews/diagnostic/mocks/data/subscribers.json
new file mode 100644
index 0000000..e84673d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/subscribers.json
@@ -0,0 +1,38 @@
+[
+   {
+      "humanReadableName":"Marc Twain",
+      "id":1,
+      "created":"2016-02-17T19:36:04.167Z",
+      "updated":"2016-02-17T19:36:05.413Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "kind":"CordSubscriberRoot",
+      "name":"Marc Twain",
+      "service_specific_attribute":"{\"url_filter_enable\": false, \"cdn_enable\": false, \"url_filter_level\": \"R\", \"users\": [{\"mac\": \"01:02:03:04:05:06\", \"level\": \"PG_13\", \"id\": 0, \"name\": \"Mom's PC\"}, {\"mac\": \"34:36:3B:C9:B6:A6\", \"id\": 1, \"name\": \"Jill's Laptop\", \"level\": \"PG_13\"}, {\"mac\": \"68:5B:35:9D:91:D5\", \"level\": \"PG_13\", \"id\": 2, \"name\": \"Jack's Laptop\"}, {\"id\": 3, \"mac\": \"90:E2:BA:82:F9:75\", \"name\": \"Dad's PC\", \"level\": \"PG_13\"}], \"firewall_enable\": false}",
+      "service_specific_id":"123"
+   },
+   {
+      "humanReadableName":"Jack London",
+      "id":2,
+      "created":"2016-02-17T19:36:04.167Z",
+      "updated":"2016-02-17T19:36:05.413Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "kind":"CordSubscriberRoot",
+      "name":"My House",
+      "service_specific_attribute":"{\"url_filter_enable\": false, \"cdn_enable\": false, \"url_filter_level\": \"R\", \"users\": [{\"mac\": \"01:02:03:04:05:06\", \"level\": \"PG_13\", \"id\": 0, \"name\": \"Mom's PC\"}, {\"mac\": \"34:36:3B:C9:B6:A6\", \"id\": 1, \"name\": \"Jill's Laptop\", \"level\": \"PG_13\"}, {\"mac\": \"68:5B:35:9D:91:D5\", \"level\": \"PG_13\", \"id\": 2, \"name\": \"Jack's Laptop\"}, {\"id\": 3, \"mac\": \"90:E2:BA:82:F9:75\", \"name\": \"Dad's PC\", \"level\": \"PG_13\"}], \"firewall_enable\": false}",
+      "service_specific_id":"123"
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/tenants.json b/views/ngXosViews/diagnostic/mocks/data/tenants.json
new file mode 100644
index 0000000..4e7557b
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/tenants.json
@@ -0,0 +1,232 @@
+[
+    {
+        "humanReadableName": "coarse-tenant-1", 
+        "id": 1, 
+        "created": "2016-02-17T19:36:04.259Z", 
+        "updated": "2016-02-17T19:36:04.259Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "coarse", 
+        "provider_service": 1, 
+        "subscriber_service": 2, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "coarse-tenant-2", 
+        "id": 2, 
+        "created": "2016-02-17T19:36:04.600Z", 
+        "updated": "2016-02-17T19:36:04.600Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "coarse", 
+        "provider_service": 2, 
+        "subscriber_service": 3, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vCPE-tenant-4", 
+        "id": 4, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 1, \"creator_id\": 1, \"wan_container_ip\": \"10.0.1.24\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "ceilometer-tenant-8", 
+        "id": 8, 
+        "created": "2016-02-17T19:36:09.370Z", 
+        "updated": "2016-02-17T20:55:19.823Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771319.823556, \"failures\": 874, \"last_success\": 1455737795.314296, \"exponent\": 874, \"last_failure\": 1455742519.823559}", 
+        "backend_status": "2 - Exception('defer object ceilometer-tenant-8 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "ceilometer", 
+        "provider_service": 6, 
+        "subscriber_service": null, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 7, \"creator_id\": 1, \"use_same_instance_for_multiple_tenants\": true}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vBNG-tenant-5", 
+        "id": 5, 
+        "created": "2016-02-17T19:36:04.769Z", 
+        "updated": "2016-02-17T20:55:21.385Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771321.384039, \"last_failure\": 1455742521.384043, \"last_success\": 1455737796.18277, \"exponent\": 881, \"failures\": 881}", 
+        "backend_status": "2 - Exception('defer object vBNG-tenant-5 due to does not have a WAN IP yet',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vBNG", 
+        "provider_service": 1, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 4, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "onos-tenant-6", 
+        "id": 6, 
+        "created": "2016-02-17T19:36:05.048Z", 
+        "updated": "2016-02-17T20:41:16.675Z", 
+        "enacted": "2016-02-17T20:41:16.729Z", 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455741676.729897, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "onos", 
+        "provider_service": 5, 
+        "subscriber_service": 1, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"creator_id\": 1, \"dependencies\": \"org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd\", \"name\": \"vBNG_ONOS_app\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vOLT-tenant-3", 
+        "id": 3, 
+        "created": "2016-02-17T19:36:04.631Z", 
+        "updated": "2016-02-17T20:28:30.428Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vOLT", 
+        "provider_service": 3, 
+        "subscriber_service": null, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": 1, 
+        "service_specific_id": "123", 
+        "service_specific_attribute": "{\"creator_id\": 1, \"c_tag\": \"432\", \"s_tag\": \"222\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "onos-tenant-7", 
+        "id": 7, 
+        "created": "2016-02-17T19:36:05.089Z", 
+        "updated": "2016-02-17T20:40:54.451Z", 
+        "enacted": "2016-02-17T20:40:54.468Z", 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455741654.468755, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "onos", 
+        "provider_service": 4, 
+        "subscriber_service": 3, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"creator_id\": 1, \"dependencies\": \"org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher\", \"name\": \"vOLT_ONOS_app\", \"install_dependencies\": \"onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar\"}", 
+        "connect_method": "na"
+    },
+    {
+        "humanReadableName": "vCPE-tenant-4", 
+        "id": 14, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 11, \"creator_id\": 1}", 
+        "connect_method": "na"
+    },
+    {
+        "humanReadableName": "vCPE-tenant-5", 
+        "id": 14, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 12, \"creator_id\": 1}", 
+        "connect_method": "na"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/users.json b/views/ngXosViews/diagnostic/mocks/data/users.json
new file mode 100644
index 0000000..4cf36f7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/users.json
@@ -0,0 +1,25 @@
+[
+  {
+    "mac": "01:02:03:04:05:06",
+    "level": "PG_13",
+    "id": 0,
+    "name": "Mom's PC"
+  },
+  {
+    "mac": "34:36:3B:C9:B6:A6",
+    "id": 1,
+    "level": "PG_13"
+  },
+  {
+    "mac": "68:5B:35:9D:91:D5",
+    "level": "PG_13",
+    "id": 2,
+    "name": "Jack's Laptop"
+  },
+  {
+    "id": 3,
+    "mac": "90:E2:BA:82:F9:75",
+    "name": "Dad's PC",
+    "level": "PG_13"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json b/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json
new file mode 100644
index 0000000..7b83f5d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json
@@ -0,0 +1,557 @@
+[
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average CPU utilization", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "cpu_util", 
+        "unit": "%", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 34.39350127615451, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of VCPUs", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "vcpus", 
+        "unit": "vcpu", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Volume of RAM", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "memory", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 2048.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "CPU time used", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "cpu", 
+        "unit": "ns", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 199610924583333.34, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Volume of RAM used", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "memory.usage", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1931.625, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0001851851851851852, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 14088.506944444445, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.015026113884266964, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.02625256131755716, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 66.71527777777777, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 9.25925925925926e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 8747.979166666666, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 111.22222222222223, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.603090277777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1486894584.4722223, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1248.113658402975, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 143.5401912417864, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 12888749.868055556, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.5918200296505445, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 28949696952.67361, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 13835573.3125, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6808.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.014062500000000002, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.013333333333333332, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 42.958333333333336, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 7230.0625, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 40.958333333333336, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6773.333333333333, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.014062500000000002, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.013325938251063044, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 44.77777777777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 7365.5, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 40.77777777777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json b/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json
new file mode 100644
index 0000000..660c9f8
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json
@@ -0,0 +1,44 @@
+[
+  {
+    "url": "subscribers",
+    "base": "xos/",
+    "methods": ["GET"],
+    "param": "id"
+  },
+  {
+    "url": "users",
+    "base": "xoslib/rs/subscriber/1/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "services",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "tenants",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "nodes",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "instances",
+    "base": "xos/",
+    "methods": ["GET"],
+    "param": "id"
+  },
+  {
+    "url": "meterstatistics",
+    "base": "xoslib/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "xos-instance-statistics",
+    "base": "xoslib/",
+    "methods": ["GET"]
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/package.json b/views/ngXosViews/diagnostic/package.json
new file mode 100644
index 0000000..91845da
--- /dev/null
+++ b/views/ngXosViews/diagnostic/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-serviceTopology",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "dev": "NODE_ENV=mock gulp serve",
+    "prebuild": "npm install && bower install",
+    "server": "easy-mocker -c ./mocks/diagnostic.conf.json -d ./mocks/data",
+    "build": "gulp",
+    "test": "karma start",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/diagnostic/spec/.eslintrc b/views/ngXosViews/diagnostic/spec/.eslintrc
new file mode 100644
index 0000000..c1764a5
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/.eslintrc
@@ -0,0 +1,15 @@
+{
+    "globals" :{
+        "describe": true,
+        "xdescribe": true,
+        "beforeEach": true,
+        "it": true,
+        "inject": true,
+        "expect": true,
+        "jasmine": true
+    },
+    "rules": {
+      "max-nested-callbacks": [0, 4],
+      "camelcase": 0
+    }
+}
diff --git a/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js b/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js
new file mode 100644
index 0000000..94307f5
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js
@@ -0,0 +1,62 @@
+(function () {
+  'use strict';
+
+  describe('The Logic Topology Helper Service', () => {
+    
+    var Service, Config;
+
+    var x0, x1, x2, x3, x4;
+
+    var svgWidth = 900;
+
+    beforeEach(module('xos.serviceTopology'));
+
+    // inject the rackHelper service
+    beforeEach(inject(function (_LogicTopologyHelper_, _serviceTopologyConfig_) {
+      // The injector unwraps the underscores (_) from around the parameter names when matching
+      Service = _LogicTopologyHelper_;
+      Config = _serviceTopologyConfig_;
+
+      // result
+      let totalElWidth = Config.elWidths.reduce((el, val) => val + el, 0);
+      let remainingSpace = svgWidth - totalElWidth - (Config.widthMargin * 2);
+      let step = remainingSpace / (Config.elWidths.length - 1);
+      x0 = Config.widthMargin;
+      x1 = x0 + Config.elWidths[0] + step;
+      x2 = x1 + Config.elWidths[1] + step;
+      x3 = x2 + Config.elWidths[2] + step;
+      x4 = x3 + Config.elWidths[3] + step;
+    }));
+
+    var customMatchers = {
+      toBeSimilar: () => {
+
+        const tolerance = 0.1;
+
+        return {
+          compare: (actual, expected) => {
+            return {
+              pass: (Math.abs(actual - expected) < tolerance),
+              message: `Expected ${actual} to be ${expected}`
+            }
+          }
+        }
+      }
+    };
+
+    beforeEach(function() {
+      jasmine.addMatchers(customMatchers);
+    });
+
+    it('should calculate horizontal position for each element', () => {
+      let [el0x, el1x, el2x, el3x, el4x] = Service.computeElementPosition(svgWidth);
+      console.log(x1, el1x);
+      expect(el0x).toBeSimilar(svgWidth - (x0 + (Config.elWidths[0] / 2)));
+      expect(el1x).toBeSimilar(svgWidth - (x1 + (Config.elWidths[1] / 2)));
+      expect(el2x).toBeSimilar(svgWidth - (x2 + (Config.elWidths[2] / 2)));
+      expect(el3x).toBeSimilar(svgWidth - (x3 + (Config.elWidths[3] / 2)));
+      expect(el4x).toBeSimilar(svgWidth - (x4 + (Config.elWidths[4] / 2)));
+    });
+  });
+
+})();
diff --git a/views/ngXosViews/diagnostic/spec/rackHelper.test.js b/views/ngXosViews/diagnostic/spec/rackHelper.test.js
new file mode 100644
index 0000000..9f11686
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/rackHelper.test.js
@@ -0,0 +1,187 @@
+(function () {
+  'use strict';
+
+  const computeNodes = [
+    {
+      humanReadableName: 'cp-1.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-3'
+        },
+        {
+          instance_name: 'mysite_clients-4'
+        },
+        {
+          instance_name: 'mysite_clients-5'
+        }
+      ]
+    },
+    {
+      humanReadableName: 'cp-2.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-1'
+        },
+        {
+          instance_name: 'mysite_clients-2'
+        }
+      ]
+    },
+    {
+      humanReadableName: 'cp-2.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-1'
+        },
+        {
+          instance_name: 'mysite_clients-2'
+        }
+      ]
+    }
+  ];
+
+  describe('The Rack Helper Service', () => {
+    
+    var Service, Config;
+
+    // results
+    var cp1, cp2, cp3, rack, instancePos, nodePos;
+
+    beforeEach(module('xos.serviceTopology'));
+
+    // inject the rackHelper service
+    beforeEach(inject(function (_RackHelper_, _serviceTopologyConfig_) {
+      // The injector unwraps the underscores (_) from around the parameter names when matching
+      Service = _RackHelper_;
+      Config = _serviceTopologyConfig_;
+
+      cp1 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: (Config.instance.height * 2) + (Config.instance.margin * 5) + Config.computeNode.labelHeight
+      };
+
+      cp2 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: Config.instance.height + (Config.instance.margin * 4) + Config.computeNode.labelHeight
+      };
+
+      cp3 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: Config.instance.height + (Config.instance.margin * 4) + Config.computeNode.labelHeight
+      };
+
+      rack = {
+        width: cp1.width + (Config.computeNode.margin * 2),
+        height: cp1.height + cp2.height + cp3.height + (Config.computeNode.margin * 4)
+      }
+
+      instancePos = [
+        {
+          x: Config.instance.margin,
+          y: Config.instance.margin + Service.getComputeNodeLabelSize()
+        },
+        {
+          x: Config.instance.margin + (Config.instance.width * 1) + (Config.instance.margin * 1),
+          y: Config.instance.margin + Service.getComputeNodeLabelSize()
+        },
+        {
+          x: Config.instance.margin,
+          y: Config.instance.margin + Service.getComputeNodeLabelSize() + + (Config.instance.height * 1) + (Config.instance.margin * 1)
+        },
+        {
+          x: Config.instance.margin + (Config.instance.width * 1) + (Config.instance.margin * 1),
+          y: Config.instance.margin + Service.getComputeNodeLabelSize() + + (Config.instance.height * 1) + (Config.instance.margin * 1)
+        }
+      ];
+
+      nodePos = [
+        {
+          x: Config.computeNode.margin,
+          y: Config.computeNode.margin
+        },
+        {
+          x: Config.computeNode.margin,
+          y: (Config.computeNode.margin * 2) + cp1.height
+        },
+        {
+          x: Config.computeNode.margin,
+          y: (Config.computeNode.margin * 3) + cp1.height + cp2.height
+        }
+      ]
+    }));
+
+    describe('Given a list of instances', () => {
+      it('should calculate the first Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[0].instances);
+        expect(width).toBe(cp1.width);
+        expect(height).toBe(cp1.height);
+      });
+
+      it('should calculate the second Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[1].instances);
+        expect(width).toBe(cp2.width);
+        expect(height).toBe(cp2.height);
+      });
+
+      it('should calculate the third Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[1].instances);
+        expect(width).toBe(cp3.width);
+        expect(height).toBe(cp3.height);
+      });
+    });
+
+    describe('Given a list of Compute Nodes', () => {
+      it('should return rack size', () => {
+        const [width, height] = Service.getRackSize(computeNodes);
+        expect(width).toBe(rack.width);
+        expect(height).toBe(rack.height);
+      });
+    });
+
+    describe('Given an instance index', () => {
+      it('should return the position for first instance', () => {
+        const [x, y] = Service.getInstancePosition(0);
+        expect(x).toBe(instancePos[0].x);
+        expect(y).toBe(instancePos[0].y);
+      })
+
+      it('should return the position for second instance', () => {
+        const [x, y] = Service.getInstancePosition(1);
+        expect(x).toBe(instancePos[1].x);
+        expect(y).toBe(instancePos[1].y);
+      });
+
+      it('should return the position for third instance', () => {
+        const [x, y] = Service.getInstancePosition(2);
+        expect(x).toBe(instancePos[2].x);
+        expect(y).toBe(instancePos[2].y);
+      });
+
+      it('should return the position for 4th instance', () => {
+        const [x, y] = Service.getInstancePosition(3);
+        expect(x).toBe(instancePos[3].x);
+        expect(y).toBe(instancePos[3].y);
+      });
+    });
+
+    describe('Given an ComputeNode index', () => {
+      it('should return the position for 1st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 0);
+        expect(x).toBe(nodePos[0].x);
+        expect(y).toBe(nodePos[0].y);
+      })
+
+      it('should return the position for 2st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 1);
+        expect(x).toBe(nodePos[1].x);
+        expect(y).toBe(nodePos[1].y);
+      });
+
+      it('should return the position for 2st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 2);
+        expect(x).toBe(nodePos[2].x);
+        expect(y).toBe(nodePos[2].y);
+      });
+    });
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/spec/serviceChain.test.js b/views/ngXosViews/diagnostic/spec/serviceChain.test.js
new file mode 100644
index 0000000..8dfa02d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/serviceChain.test.js
@@ -0,0 +1,211 @@
+'use strict';
+
+describe('The Service Relation Service', () => {
+  
+  var Service;
+
+  beforeEach(module('xos.serviceTopology'));
+  beforeEach(module('templates'));
+
+  // inject the cartService
+  beforeEach(inject(function (_ServiceRelation_) {
+    // The injector unwraps the underscores (_) from around the parameter names when matching
+    Service = _ServiceRelation_;
+  }));
+
+  describe('given a service', () => {
+
+    const levelRelations = [
+      {
+        subscriber_service: 1
+      },
+      {
+        subscriber_service: 1
+      },
+      {
+        subscriber_service: 2
+      }
+    ];
+
+    it('should find all involved relations', () => {
+      expect(typeof Service.findLevelRelation).toBe('function');
+      let levelRelation = Service.findLevelRelation(levelRelations, 1);
+      expect(levelRelation.length).toBe(2);
+    });
+  });
+
+  describe('given a set of relation', () => {
+
+    const levelRelations = [
+      {
+        provider_service: 1,
+        service_specific_attribute: '{"instance_id": "instance1"}',
+        subscriber_tenant: 2
+      },
+      {
+        provider_service: 2
+      }
+    ];
+
+    const services = [
+      {
+        id: 1
+      },
+      {
+        id: 2
+      },
+      {
+        id: 3
+      }
+    ];
+
+    it('should find all the provider service', () => {
+      expect(typeof Service.findLevelServices).toBe('function');
+      let levelServices = Service.findLevelServices(levelRelations, services);
+      expect(levelServices.length).toBe(2);
+    });
+
+    it('should retrieve all service specific information', () => {
+      let info = Service.findSpecificInformation(levelRelations, 1);
+      expect(info.instance_id).toBe('instance1');
+    });
+  });
+
+
+
+  describe('given a list of services and a list of relations', () => {
+
+    const services = [
+      {
+        id: 1,
+        humanReadableName: 'service-1'
+      },
+      {
+        id: 2,
+        humanReadableName: 'service-2'
+      },
+      {
+        id: 3,
+        humanReadableName: 'service-3'
+      },
+      {
+        id: 4,
+        humanReadableName: 'service-4'
+      }
+    ];
+
+    const tenants = [
+      {
+        id: 1,
+        provider_service: 2,
+        subscriber_tenant: 4,
+        subscriber_service: 1,
+      },
+      {
+        id: 2,
+        provider_service: 3,
+        subscriber_tenant: 1,
+        subscriber_service: 2
+      },
+      {
+        id: 3,
+        provider_service: 4,
+        subscriber_tenant: 4,
+        subscriber_service: 1
+      },
+      {
+        id: 4,
+        subscriber_root: 1,
+        provider_service: 1
+      }
+    ];
+
+    it('should return a tree ordered by tenants', () => {
+      let tree = Service.buildSubscriberServiceTree(services, tenants);
+
+      expect(tree.name).toBe('fakeSubs');
+      expect(tree.parent).toBeNull();
+      expect(tree.children.length).toBe(1);
+
+      expect(tree.children[0].name).toBe('service-1');
+      expect(tree.children[0].parent).toBeNull();
+      expect(tree.children[0].tenant).toEqual({id: 4, subscriber_root: 1, provider_service: 1});
+      expect(tree.children[0].children.length).toBe(2);
+
+      expect(tree.children[0].children[0].name).toBe('service-2');
+      expect(tree.children[0].children[0].tenant).toEqual({ id: 1, provider_service: 2, subscriber_tenant: 4, subscriber_service: 1 });;
+      expect(tree.children[0].children[0].children[0].name).toBe('service-3');
+
+      expect(tree.children[0].children[0].children[0].children[0].name).toBe('Router');
+
+      expect(tree.children[0].children[1].name).toBe('service-4');
+      expect(tree.children[0].children[1].children[0].name).toBe('Router');
+    });
+  });
+
+  describe('given an object', () => {
+
+    const sample = {
+      name: '1',
+      children: [
+        {
+          name: '2',
+          children: [
+            {
+              name: '3'
+            }
+          ]
+        }
+      ]
+    };
+
+    it('should return the depth', () => {
+      expect(Service.depthOf(sample)).toBe(3);
+    });
+  });
+
+  describe('Given a list of services and COARSE tenant', () => {
+    
+    const coarseTenants = [
+      {
+        humanReadableName: 'coarse-1',
+        provider_service: 1,
+        subscriber_service: 2
+      },
+      {
+        humanReadableName: 'coarse-2',
+        provider_service: 2,
+        subscriber_service: 3
+      }
+    ];
+
+    const services = [
+      {
+        id: 1,
+        name: 'vbng',
+        humanReadableName: 'vbng'
+      },
+      {
+        id: 2,
+        name: 'vsg',
+        humanReadableName: 'vsg'
+      },
+      {
+        id: 3,
+        name: 'volt',
+        humanReadableName: 'volt'
+      }
+    ];
+
+    it('should build the tenancy graph', () => {
+      let tree = Service.buildServiceTree(services, coarseTenants);
+
+      expect(tree.type).toBe('subscriber');
+      expect(tree.children[0].name).toBe('volt');
+      expect(tree.children[0].service).toBeDefined();
+      expect(tree.children[0].children[0].name).toBe('vsg');
+      expect(tree.children[0].children[0].children[0].name).toBe('vbng');
+    });
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/css/dev.css b/views/ngXosViews/diagnostic/src/css/dev.css
new file mode 100644
index 0000000..7ff2305
--- /dev/null
+++ b/views/ngXosViews/diagnostic/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/views/ngXosViews/diagnostic/src/css/diagnostic.css b/views/ngXosViews/diagnostic/src/css/diagnostic.css
new file mode 100644
index 0000000..503c2de
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/css/diagnostic.css
@@ -0,0 +1,312 @@
+/* CONTAINER */
+#xosDiagnostic, [ui-view] {
+    height: 100%;
+}
+
+diagnostic-container .half-height {
+    position: relative;
+    height: 50%;
+}
+
+diagnostic-container .onethird-height {
+    position: relative;
+    height: 33%;
+}
+
+diagnostic-container .twothird-height {
+    position: relative;
+    height: 67%;
+}
+
+diagnostic-container .subscriber-select{
+    max-width: 200px;
+    position: absolute;
+    top: 20px;
+    right: 20px;
+    z-index: 1;
+}
+
+.half-height + .half-height {
+    border-top: 1px solid black;
+}
+
+service-topology,
+logic-topology {
+    height: 100%;
+    width: 100%;
+    display: block;
+    position: absolute;
+    top: 0;
+}
+
+logic-topology .subscriber circle,
+logic-topology .device circle{
+    fill: #fff;
+    stroke: green;
+    stroke-width: 1px;
+}
+
+logic-topology > svg {
+    position: absolute;
+    top: 0;
+}
+
+/* CLOUDS */
+
+logic-topology .network .cloud {
+    fill: #fff;
+    stroke: green;
+    stroke-width: 1px;   
+}
+
+/* RACK */
+logic-topology .node.rack > g > rect{
+    fill: #ccc;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+/* CP NODE */
+
+logic-topology .compute-node > rect{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+/* INSTANCE */
+
+logic-topology .instance > rect{
+    fill: #eee;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+logic-topology .node .instance.active rect{
+    fill: lightsteelblue;
+    stroke: steelblue;
+    stroke-width: 1px;   
+}
+
+logic-topology .node .instance.active.good > rect{
+    fill: green;
+}
+
+logic-topology .node .instance.active.provisioning > rect{
+    fill: yellow;
+}
+
+logic-topology .node .instance.active.bad > rect{
+    fill: red;
+}
+
+/* INSTANCE STATS */
+
+logic-topology .node .instance .stats-container rect {
+  fill: white;
+}
+
+logic-topology .node .instance .stats-container text.name{
+  font-weight: bold;
+}
+
+logic-topology .node .instance .stats-container text.ip{
+  font-style: italic;
+  font-size: 10px;
+}
+
+/* CONTAINERS */
+logic-topology .node .instance .stats-container .container rect {
+  fill: #eee;
+  stroke: steelblue;
+  stroke-width: 1px;
+}
+
+/* LEGEND */
+
+.legend {
+    fill: #fff;
+    stroke: #ccc;
+    stroke-width: 1px;
+    position: relative;
+}
+
+.legend text {
+    stroke: #000;
+}
+
+.node {
+    cursor: pointer;
+}
+
+.node circle,
+.node rect{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+.node.subscriber circle,
+.node.subscriber rect,
+.node.router circle,
+.node.router rect {
+    stroke: #05ffcb;
+}
+
+.node.slice rect {
+    stroke: #b01dff;
+}
+
+.node.instance rect {
+    stroke: #ccc;
+}
+
+.node.instance rect.active {
+    stroke: #ff8b00;
+}
+
+.node rect.slice-detail{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 3px;
+}
+
+.node text {
+    font: 12px sans-serif;
+}
+
+.link, .device-link {
+    fill: none;
+    stroke: #ccc;
+    stroke-width: 2px;
+}
+
+.link.slice {
+    stroke: rgba(157, 4, 183, 0.29);
+}
+.link.instance{
+    stroke: #ccc;
+}
+
+.link.instance.active{
+    stroke: rgba(255, 138, 0, 0.65);
+}
+
+.service-details{
+    width: 200px;
+    position: absolute;
+    top: 20px;
+    right: 20px;
+}
+
+/* when showing the thing */
+
+.animate.ng-hide-remove {
+    animation:0.5s bounceInRight ease;
+}
+
+/* when hiding the picture */
+.animate.ng-hide-add {
+    animation:0.5s bounceOutRight ease;
+}
+
+/* LOADER */
+.loader {
+  font-size: 10px;
+  margin: 150px auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: load3 1.4s infinite linear;
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #105E9E;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+
+/* MODALS */
+
+.modal.fade.in {
+  display: block;
+}
+
+/* ANIMATIONS */
+
+@keyframes bounceInRight {
+    from, 60%, 75%, 90%, to {
+        animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+    }
+
+    from {
+        opacity: 0;
+        transform: translate3d(3000px, 0, 0);
+    }
+
+    60% {
+        opacity: 1;
+        transform: translate3d(-25px, 0, 0);
+    }
+
+    75% {
+        transform: translate3d(10px, 0, 0);
+    }
+
+    90% {
+        transform: translate3d(-5px, 0, 0);
+    }
+
+    to {
+        transform: none;
+    }
+}
+
+@keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    transform: translate3d(-20px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(2000px, 0, 0);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/index.html b/views/ngXosViews/diagnostic/src/index.html
new file mode 100644
index 0000000..dcba923
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/index.html
@@ -0,0 +1,48 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/diagnostic.css">
+<!-- endinject -->
+
+<div ng-app="xos.diagnostic" id="xosDiagnostic">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/jquery/dist/jquery.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.min.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/subscriber-modal.js"></script>
+<script src="/.tmp/serviceTopologyHelper.js"></script>
+<script src="/.tmp/serviceTopology.js"></script>
+<script src="/.tmp/rest_services.js"></script>
+<script src="/.tmp/rackHelper.js"></script>
+<script src="/.tmp/nodeDrawer.js"></script>
+<script src="/.tmp/logicTopologyHelper.js"></script>
+<script src="/.tmp/logicTopology.js"></script>
+<script src="/.tmp/diagnostic.js"></script>
+<script src="/.tmp/d3.js"></script>
+<script src="/.tmp/config.js"></script>
+<script src="/.tmp/chart_data_service.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/diagnostic/src/js/chart_data_service.js b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
new file mode 100644
index 0000000..609b27b
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
@@ -0,0 +1,207 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('ChartData', function($rootScope, $q, lodash, Tenant, Node, serviceTopologyConfig, Ceilometer, Instances) {
+    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'
+                  }] //subscribers goes here
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    };
+
+    this.getLogicTree = () => {
+      const deferred = $q.defer();
+
+      Node.queryWithInstances().$promise
+        .then((computeNodes) => {
+          this.logicTopologyData.children[0].children[0].computeNodes = computeNodes;
+          // LogicTopologyHelper.updateTree(svg);
+          deferred.resolve(this.logicTopologyData);
+        });
+
+      return deferred.promise;
+    };
+
+    /**
+    * Add Subscriber tag to LAN Network
+    */
+    this.addSubscriberTag = (tags) => {
+      this.logicTopologyData.children[0].children[0].children[0].subscriberTag = {
+        cTag: tags.c_tag,
+        sTag: tags.s_tag
+      };
+    };
+
+    /**
+    * Add Subscribers to the tree
+    */
+    this.addSubscriber = (subscriber) => {
+      subscriber.children = subscriber.devices;
+
+      // add subscriber to data tree
+      this.logicTopologyData.children[0].children[0].children[0].children = [subscriber];
+      return this.logicTopologyData;
+    };
+
+    this.getSubscriberTag = () => {
+      const tags = JSON.parse(this.currentServiceChain.children[0].tenant.service_specific_attribute);
+      delete tags.creator_id;
+      
+      this.addSubscriberTag(tags);
+      // add tags info to current subscriber
+      this.currentSubscriber.tags = {
+        cTag: tags.c_tag,
+        sTag: tags.s_tag
+      };
+
+    };
+
+    this.getSubscriberIP = () => {
+      const ip = JSON.parse(this.currentServiceChain.children[0].children[0].tenant.service_specific_attribute).wan_container_ip;
+      // const ip = this.currentServiceChain.children[0].children[0].tenant.wan_container_ip;
+      this.logicTopologyData.children[0].subscriberIP = ip;
+    };
+
+    this.selectSubscriber = (subscriber) => {
+
+      // append the device with to config settings
+      serviceTopologyConfig.elWidths.push(160);
+
+      this.addSubscriber(angular.copy(subscriber));
+
+      //clean selected instances
+      this.highlightInstances([]);
+
+      this.getSubscriberTag();
+      this.getSubscriberIP();
+
+    };
+
+    this.highlightInstances = (instances) => {
+
+      const computeNodes = this.logicTopologyData.children[0].children[0].computeNodes;
+
+      // unselect all
+      computeNodes.map((node) => {
+        node.instances.map((instance) => {
+          instance.selected = false
+          return instance;
+        });
+      });
+
+      lodash.forEach(instances, (instance) => {
+        computeNodes.map((node) => {
+          node.instances.map((d3instance) => {
+            if(d3instance.id === instance.id){
+              // console.log(d3instance, instance);
+              d3instance.selected = true;
+              d3instance.stats = instance.stats; //add stats to d3 node
+              d3instance.container = instance.container; // container info to d3 node
+            }
+            return d3instance;
+          });
+        });
+      });
+
+    }
+
+    this.getInstanceStatus = (service) => {
+      const deferred = $q.defer();
+
+      let p;
+
+      // subscriber specific
+      if(this.currentSubscriber){
+
+        let attr;
+        try {
+          attr = JSON.parse(service.tenant.service_specific_attribute);
+        }
+        catch(e){
+          attr = null;
+        }
+        
+        // if no instances are associated to the subscriber
+        if(!attr || !attr.instance_id){
+          let d = $q.defer();
+          d.resolve([]);
+          p = d.promise;
+        }
+        // if ther is an instance
+        else{
+          let instance = {};
+          p = Instances.get({id: attr.instance_id}).$promise
+          .then(function(_instance){
+            instance = _instance;
+            return Ceilometer.getInstanceStats(instance.instance_uuid);
+          })
+          .then((stats) => {
+            instance.stats = stats;
+            const containerName = `vcpe-${this.currentSubscriber.tags.sTag}-${this.currentSubscriber.tags.cTag}`;
+            // append containers
+            instance.container = {
+              name: containerName
+            };
+
+            // TODO fetch container stats
+            return Ceilometer.getContainerStats(containerName);
+          })
+          .then((containerStats) => {
+            instance.container.stats = containerStats.stats;
+            instance.container.port = containerStats.port;
+            return [instance];
+          });
+        }
+      }
+      // global scope
+      else {
+        const param = {
+          'service_vsg': {kind: 'vCPE'},
+          'service_vbng': {kind: 'vBNG'},
+          'service_volt': {kind: 'vOLT'}
+        };
+
+        p = Tenant.queryVsgInstances(param[service.name]).$promise
+        .then((instances) => {
+
+          return Ceilometer.getInstancesStats(instances);
+        });
+      }
+
+      p.then((instances) => {
+        this.highlightInstances(instances);
+        deferred.resolve(instances);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      });
+
+      return deferred.promise;
+    };
+  })
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/config.js b/views/ngXosViews/diagnostic/src/js/config.js
new file mode 100644
index 0000000..75b5fe7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/config.js
@@ -0,0 +1,51 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .constant('serviceTopologyConfig', {
+    widthMargin: 20,
+    heightMargin: 30,
+    duration: 750,
+    elWidths: [20, 104, 105, 104, 20], //this is not true
+    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
+    }
+  })
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/d3.js b/views/ngXosViews/diagnostic/src/js/d3.js
new file mode 100644
index 0000000..b56ee8f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/d3.js
@@ -0,0 +1,9 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .factory('d3', function($window){
+    return $window.d3;
+  })
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/diagnostic.js b/views/ngXosViews/diagnostic/src/js/diagnostic.js
new file mode 100644
index 0000000..6638a95
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/diagnostic.js
@@ -0,0 +1,44 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('diagnosticContainer', function(){
+    return {
+      restrict: 'E',
+      templateUrl: 'templates/diagnostic.tpl.html',
+      controllerAs: 'vm',
+      controller: function(ChartData, Subscribers, ServiceRelation, $rootScope, $log){
+
+        this.loader = true;
+        this.error = false;
+        Subscribers.query().$promise
+        .then((subscribers) => {
+          this.subscribers = subscribers;
+          return ServiceRelation.get();
+        })
+        .then((serviceChain) => {
+          this.serviceChain = serviceChain;
+        })
+        .catch(e => {
+          throw new Error(e);
+          this.error = e;
+        })
+        .finally(() => {
+          this.loader = false;
+        });
+
+        $rootScope.$on('subscriber.selected', (evt, subscriber) => {
+          ServiceRelation.getBySubscriber(subscriber)
+          .then((serviceChain) => {
+            this.serviceChain = serviceChain;
+            ChartData.currentServiceChain = serviceChain;
+            return Subscribers.getWithDevices({id: subscriber.id}).$promise;
+          })
+          .then((subscriber) => {
+            this.selectedSubscriber = subscriber;
+            ChartData.currentSubscriber = subscriber;
+          });
+        });
+      }
+    }
+  });
+})(); 
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopology.js b/views/ngXosViews/diagnostic/src/js/logicTopology.js
new file mode 100644
index 0000000..ce81bec
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/logicTopology.js
@@ -0,0 +1,84 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('logicTopology', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        subscribers: '=',
+        selected: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/logicTopology.tpl.html',
+      controller: function($element, $log, $scope, $rootScope, $timeout, d3, LogicTopologyHelper, Node, Tenant, Ceilometer, serviceTopologyConfig, ChartData){
+        $log.info('Logic Plane');
+
+        var svg;
+        this.selectedInstances = [];
+        this.hideInstanceStats = true;
+
+        const handleSvg = (el) => {
+
+          svg = d3.select(el)
+          .append('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+        }
+
+        ChartData.getLogicTree()
+        .then((tree) => {
+          LogicTopologyHelper.updateTree(svg);
+        });
+
+        $scope.$watch(() => this.selected, (selected) => {
+          if(selected){
+            ChartData.selectSubscriber(selected);
+            LogicTopologyHelper.updateTree(svg);
+          }
+        });
+
+        $rootScope.$on('instance.detail.hide', () => {
+          this.hideInstanceStats = true;
+          $timeout(() => {
+            this.selectedInstances = [];
+            ChartData.highlightInstances([]);
+            LogicTopologyHelper.updateTree(svg);
+          }, 500);
+        });
+
+        $rootScope.$on('instance.detail', (evt, service) => {
+          ChartData.getInstanceStatus(service)
+          .then((instances) => {
+            // this.hideInstanceStats = false;
+            // // HACK if array is empty wait for animation
+            // if(instances.length === 0){
+            //   this.hideInstanceStats = true;
+            //   $timeout(() => {
+            //     this.selectedInstances = instances;
+            //   }, 500);
+            // }
+            // else{
+            //   this.selectedInstances = instances;
+            // }
+            LogicTopologyHelper.updateTree(svg);
+          })
+        })
+
+        handleSvg($element[0]);
+        LogicTopologyHelper.setupTree(svg);
+
+        this.openSubscriberModal = () => {
+          this.subscriberModal = true;
+          $scope.$apply();
+        };
+
+        // listen for subscriber modal event
+        $rootScope.$on('subscriber.modal.open', () => {
+          this.openSubscriberModal();
+        });
+
+      }
+    };
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
new file mode 100644
index 0000000..51ac0f7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
@@ -0,0 +1,177 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('LogicTopologyHelper', function($window, $log, $rootScope, lodash, serviceTopologyConfig, NodeDrawer, ChartData){
+
+    var diagonal, nodes, links, i = 0, svgWidth, svgHeight, layout;
+
+    const baseData = ChartData.logicTopologyData;
+
+    /**
+     * Calculate the horizontal position for each element.
+     * subsrcribers, devices and routers have the same fixed width 20
+     * network have a fixed width 104
+     * rack have a fixed width 105
+     * build and array of 6 elements representing the position of each element in the svg
+     * to equally space them
+     */
+
+    this.computeElementPosition = (svgWidth) => {
+
+      let xPos = [];
+
+      let totalElWidth = lodash.reduce(serviceTopologyConfig.elWidths, (el, val) => val + el, 0);
+
+      let remainingSpace = svgWidth - totalElWidth - (serviceTopologyConfig.widthMargin * 2);
+
+      let step = remainingSpace / (serviceTopologyConfig.elWidths.length - 1);
+
+      lodash.forEach(serviceTopologyConfig.elWidths, (el, i) => {
+
+        // get half of the previous elements width
+        let previousElWidth = 0;
+        if(i !== 0){
+          previousElWidth = lodash.reduce(serviceTopologyConfig.elWidths.slice(0, i), (el, val) => val + el, 0);
+        }
+
+        let elPos =
+          serviceTopologyConfig.widthMargin // right margin
+          + (step * i) // space between elements
+          + (el / 2) // this el width
+          + previousElWidth; // previous elements width
+
+        xPos.push(svgWidth - elPos);
+      })
+
+      return xPos
+    };
+
+    /**
+    * from a nested data structure,
+    * create nodes and links for a D3 Tree Layout
+    */
+    const computeLayout = (data) => {
+      let nodes = layout.nodes(data);
+
+      // Normalize for fixed-depth.
+      nodes.forEach((d) => {
+        // position the child node horizontally
+        d.y = this.computeElementPosition(svgWidth)[d.depth];
+      });
+
+      let links = layout.links(nodes);
+
+      return [nodes, links];
+    };
+
+    /**
+    * Draw the containing group for any node or update the existing one
+    */
+    const drawNodes = (svg, nodes) => {
+      // Update the nodes…
+      var node = svg.selectAll('g.node')
+      .data(nodes, d => {
+        if(!angular.isString(d.d3Id)){
+          d.d3Id = `tree-${++i}`;
+        }
+        return d.d3Id;
+      });
+
+      // Enter any new nodes
+      var nodeEnter = node.enter().append('g')
+      .attr({
+        class: d => `node ${d.type}`,
+        transform: `translate(${svgWidth / 2}, ${svgHeight / 2})`
+      });
+
+      // create Nodes
+      NodeDrawer.addNetworks(node.filter('.network'));
+      NodeDrawer.addRack(node.filter('.rack'));
+      NodeDrawer.addPhisical(node.filter('.router'));
+      NodeDrawer.addPhisical(node.filter('.subscriber'));
+      NodeDrawer.addDevice(node.filter('.device'));
+
+      // add event listener to subscriber
+      node.filter('.subscriber')
+      .on('click', () => {
+        $rootScope.$emit('subscriber.modal.open');
+      });
+
+      //update nodes
+      // TODO if data change, only update them
+      // NodeDrawer.updateRack(node.filter('.rack'));
+
+      // Transition nodes to their new position.
+      var nodeUpdate = node.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          'transform': d => `translate(${d.y},${d.x})`
+        });
+
+      // TODO handle node remove
+      var nodeExit = node.exit().remove();
+    };
+
+    /**
+    * Handle links in the tree layout
+    */
+    const drawLinks = (svg, links) => {
+
+      diagonal = d3.svg.diagonal()
+      .projection(d => [d.y, d.x]);
+
+      // Update the links…
+      var link = svg.selectAll('path.link')
+        .data(links, d => {
+          return d.target.d3Id
+        });
+
+      // Enter any new links at the parent's previous position.
+      link.enter().insert('path', 'g')
+        .attr('class', d => `link ${d.target.type}`)
+        .attr('d', function(d) {
+          var o = {x: svgHeight / 2, y: svgWidth / 2};
+          return diagonal({source: o, target: o});
+        });
+
+      // Transition links to their new position.
+      link.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr('d', diagonal);
+
+      link.exit().remove();
+    };
+
+    /**
+    * Calculate the svg size and setup tree layout
+    */
+    this.setupTree = (svg) => {
+      
+
+      svgWidth = svg.node().getBoundingClientRect().width;
+      svgHeight = svg.node().getBoundingClientRect().height;
+
+      const width = svgWidth - (serviceTopologyConfig.widthMargin * 2);
+      const height = svgHeight - (serviceTopologyConfig.heightMargin * 2);
+
+      layout = d3.layout.tree()
+      .size([height, width]);
+    };
+
+    /**
+    * Update the tree layout
+    */
+
+    this.updateTree = (svg) => {
+      // Compute the new tree layout.
+      [nodes, links] = computeLayout(baseData);
+
+      // console.log(baseData);
+      drawNodes(svg, nodes);
+      drawLinks(svg, links);
+    }
+
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/main.js b/views/ngXosViews/diagnostic/src/js/main.js
new file mode 100644
index 0000000..73cd3d9
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/main.js
@@ -0,0 +1,26 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic', [
+    'ngResource',
+    'ngCookies',
+    'ngLodash',
+    'ngAnimate',
+    'ui.router',
+    'xos.helpers'
+  ])
+  .config(($stateProvider) => {
+    $stateProvider
+    .state('home', {
+      url: '/',
+      template: '<diagnostic-container></diagnostic-container>'
+    });
+  })
+  .config(function($httpProvider){
+    $httpProvider.interceptors.push('NoHyperlinks');
+  })
+  .run(($log) => {
+    $log.info('Diagnostic Started');
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
new file mode 100644
index 0000000..e875426
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
@@ -0,0 +1,494 @@
+(function () {
+  'use strict';
+
+  const shapes = {
+    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'
+  }
+
+  var computeNodeId = 0;
+  var instanceId = 0;
+
+  angular.module('xos.diagnostic')
+  .service('NodeDrawer', function(d3, serviceTopologyConfig, RackHelper, lodash){
+
+    var _this = this;
+
+    this.addNetworks = (nodes) => {
+      nodes.append('path')
+      .attr({
+        d: shapes.cloud,
+        transform: 'translate(-63, -52), scale(0.5)',
+        class: 'cloud'
+      });
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'middle'
+      })
+      .text(d => d.name)
+
+      nodes.each(function(n){
+        let currentNode = d3.select(this);
+        // cicle trouch node to add Tags and Public IP
+        if(n.name === 'LAN' && angular.isDefined(n.subscriberTag)){
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 40
+          })
+          .text(() => `C-Tag: ${n.subscriberTag.cTag}`);
+
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 60
+          })
+          .text(() => `S-Tag: ${n.subscriberTag.sTag}`);
+        }
+
+        if(n.name === 'WAN' && angular.isDefined(n.subscriberIP)){
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 40
+          })
+          .text(() => `Public IP: ${n.subscriberIP}`);
+        }
+      });
+    }
+
+    this.addRack = (nodes) => {
+
+      // loop because of D3
+      // rack will be only one
+      nodes.each(d => {
+        let [w, h] = RackHelper.getRackSize(d.computeNodes);
+
+        // TODO update instead of delete and redraw
+        nodes.select('g').remove();
+
+        let rack = nodes
+        .append('g');
+
+        rack
+        .attr({
+          transform: `translate(0,0)`
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          transform: () => `translate(${- (w / 2)}, ${- (h / 2)})`
+        });
+
+        rack
+        .append('rect')
+        .attr({
+          width: 0,
+          height: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          width: w,
+          height: h
+        });
+
+        rack.append('text')
+        .attr({
+          'text-anchor': 'middle',
+          y: - 10,
+          x: w / 2,
+          opacity: 0
+        })
+        .text(d => d.name)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+        this.drawComputeNodes(rack, d.computeNodes);
+
+      });
+
+    };
+
+    this.drawComputeNodes = (container, nodes) => {
+      
+      let elements = container.selectAll('.compute-nodes')
+      .data(nodes, d => {
+        if(!angular.isString(d.d3Id)){
+          d.d3Id = `compute-node-${++computeNodeId}`;
+        }
+        return d.d3Id;
+      });
+
+      let {width, height} = container.node().getBoundingClientRect();
+
+      var nodeContainer = elements.enter().append('g');
+
+      nodeContainer
+      .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
+        class: 'compute-node',
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        transform: (d) => `translate(${RackHelper.getComputeNodePosition(nodes, d.d3Id.replace('compute-node-', '') - 1)})`
+      });
+
+      nodeContainer.append('rect')
+      .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        width: d => RackHelper.getComputeNodeSize(d.instances)[0],
+        height: d => RackHelper.getComputeNodeSize(d.instances)[1],
+      });
+
+      nodeContainer.append('text')
+      .attr({
+        'text-anchor': 'start',
+        y: 15, //FIXME
+        x: 10, //FIXME
+        opacity: 0
+      })
+      .text(d => d.humanReadableName.split('.')[0])
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      })
+
+      // if there are Compute Nodes
+      if(nodeContainer.length > 0){
+        // draw instances for each compute node
+        nodeContainer.each(function(a){
+          _this.drawInstances(d3.select(this), a.instances);
+        })
+      }
+
+    };
+
+    // NOTE Stripping unuseful names to shorten labels.
+    // This is not elegant
+    const formatInstanceName = (name) => {
+      return name
+        .replace('app_', '')
+        .replace('service_', '')
+        // .replace('ovs_', '')
+        .replace('mysite_', '')
+        .replace('_instance', '');
+    };
+
+    const getInstanceStatusColor = (instance) => {
+      function startWith(val, string){
+        return string.substring(0, val.length) === val;
+      }
+
+      if(startWith('0 - ', instance.backend_status)){
+        return 'provisioning';
+      }
+      if(startWith('1 - ', instance.backend_status)){
+        return 'good';
+      }
+      if(startWith('2 - ', instance.backend_status)){
+        return 'bad';
+      }
+      else {
+        return '';
+      }
+    };
+
+    const drawContainer = (container, docker) => {
+
+      const containerBox = container.append('g')
+        .attr({
+          class: 'container',
+          transform: `translate(${serviceTopologyConfig.instance.margin}, 115)`
+        });
+
+      containerBox.append('rect')
+        .attr({
+          width: 250 - (serviceTopologyConfig.container.margin * 2),
+          height: serviceTopologyConfig.container.height,
+        });
+
+      containerBox.append('text')
+        .attr({
+          y: 20,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'name'
+        })
+        .text(docker.name)
+
+      // add stats
+      const interestingMeters = ['memory', 'memory.usage', 'cpu_util'];
+
+      interestingMeters.forEach((m, i) => {
+        const meter = lodash.find(docker.stats, {meter: m});
+        // if there is no meter stats skip rendering
+        if(!angular.isDefined(meter)){
+          return;
+        }
+        containerBox.append('text')
+        .attr({
+          y: 40 + (i * 15),
+          x: serviceTopologyConfig.instance.margin,
+          opacity: 0
+        })
+        .text(`${meter.description}: ${Math.round(meter.value)} ${meter.unit}`)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        });
+      });
+
+      // add port stats
+      const ports = ['eth0', 'eth1'];
+      const interestingPortMeters = [
+        {
+          meter: 'network.incoming.bytes.rate',
+          label: 'Incoming'
+        },
+        {
+          meter: 'network.outgoing.bytes.rate',
+          label: 'Outgoing'
+        }
+      ];
+      
+      ports.forEach((p, j) => {
+
+        // if there are no port stats skip rendering
+        if(docker.port[p].length === 0){
+          return;
+        }
+
+        containerBox.append('text')
+        .attr({
+          y: 90,
+          x: serviceTopologyConfig.instance.margin + (120 * j),
+          class: 'name'
+        })
+        .text(`${docker.name}-${p}`)
+
+        interestingPortMeters.forEach((m, i) => {
+
+          const meter = lodash.find(docker.port[p], {meter: m.meter});
+          // if there is no meter stats skip rendering
+          if(!angular.isDefined(meter)){
+            return;
+          }
+          containerBox.append('text')
+          .attr({
+            y: 105 + (i * 15),
+            x: serviceTopologyConfig.instance.margin + (120 * j),
+            opacity: 0
+          })
+          .text(`${m.label}: ${Math.round(meter.value)} ${meter.unit}`)
+          .transition()
+          .duration(serviceTopologyConfig.duration)
+          .attr({
+            opacity: 1
+          });
+        });
+      });
+    }
+
+    const showInstanceStats = (container, instance) => {
+
+      // NOTE this should be dinamically positioned
+      // base on the number of element present
+      const statsContainer = container.append('g')
+        .attr({
+          transform: `translate(200, -120)`,
+          class: 'stats-container'
+        });
+
+
+      statsContainer.append('line')
+        .attr({
+          x1: -160,
+          y1: 120,
+          x2: 0,
+          y2: 50,
+          stroke: 'black',
+          opacity: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      // NOTE rect should be dinamically sized base on the presence of a container
+      let statsHeight = 110;
+      let statsWidth = 250;
+
+      if (instance.container){
+        statsHeight += serviceTopologyConfig.container.height + (serviceTopologyConfig.container.margin * 2)
+      }
+
+      statsContainer.append('rect')
+        .attr({
+          width: statsWidth,
+          height: statsHeight,
+          opacity: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        });
+
+      // add instance info
+      statsContainer.append('text')
+        .attr({
+          y: 15,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'name',
+          opacity: 0
+        })
+        .text(instance.humanReadableName)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      statsContainer.append('text')
+        .attr({
+          y: 30,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'ip',
+          opacity: 0
+        })
+        .text(instance.ip)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      // add stats
+      const interestingMeters = ['memory', 'memory.usage', 'cpu', 'vcpus'];
+
+      interestingMeters.forEach((m, i) => {
+        const meter = lodash.find(instance.stats, {meter: m});
+        statsContainer.append('text')
+        .attr({
+          y: 55 + (i * 15),
+          x: serviceTopologyConfig.instance.margin,
+          opacity: 0
+        })
+        .text(`${meter.description}: ${Math.round(meter.value)} ${meter.unit}`)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        });
+      });
+
+      if(instance.container){
+        // draw container
+        drawContainer(statsContainer, instance.container);
+      }
+
+    };
+
+    this.drawInstances = (container, instances) => {
+      
+      // TODO check for stats field in instance and draw popup
+
+      let {width, height} = container.node().getBoundingClientRect();
+
+      let elements = container.selectAll('.instances')
+      .data(instances, d => angular.isString(d.d3Id) ? d.d3Id : d.d3Id = `instance-${++instanceId}`)
+
+      var instanceContainer = elements.enter().append('g');
+
+      instanceContainer
+      .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
+        class: d => `instance ${d.selected ? 'active' : ''} ${getInstanceStatusColor(d)}`,
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        transform: (d, i) => `translate(${RackHelper.getInstancePosition(i)})`
+      });
+
+      instanceContainer.append('rect')
+      .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        width: serviceTopologyConfig.instance.width,
+        height: serviceTopologyConfig.instance.height
+      });
+
+      instanceContainer.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: 23, //FIXME
+        x: 40, //FIXME
+        opacity: 0
+      })
+      .text(d => formatInstanceName(d.humanReadableName))
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      });
+
+      // if stats are attached and instance is active,
+      // draw stats
+      instanceContainer.each(function(instance, i){
+
+        const container = d3.select(this);
+
+        if(angular.isDefined(instance.stats) && instance.selected){
+          showInstanceStats(container, instance, i);
+        }
+      });
+
+      instanceContainer
+      .on('click', function(d){
+        console.log(`Draw vignette with stats for instance: ${d.name}`);
+      });
+    };
+
+    this.addPhisical = (nodes) => {
+      nodes.append('rect')
+      .attr(serviceTopologyConfig.square);
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: serviceTopologyConfig.square.y - 10
+      })
+      .text(d => d.name);
+    }
+
+    this.addDevice = (nodes) => {
+      nodes.append('circle')
+      .attr(serviceTopologyConfig.circle);
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'end',
+        x: - serviceTopologyConfig.circle.r - 10,
+        y: serviceTopologyConfig.circle.r / 2
+      })
+      .text(d => d.name || d.mac); 
+    }
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/rackHelper.js b/views/ngXosViews/diagnostic/src/js/rackHelper.js
new file mode 100644
index 0000000..17eb0db
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/rackHelper.js
@@ -0,0 +1,85 @@
+(function () {
+  angular.module('xos.diagnostic')
+  .service('RackHelper', function(serviceTopologyConfig, lodash){
+
+    this.getComputeNodeLabelSize = () => {
+      return serviceTopologyConfig.computeNode.labelHeight + (serviceTopologyConfig.instance.margin * 2)
+    }
+
+    /**
+    * Given a list of instance should get the Compute Node size.
+    * They are placed in rows of 2 with 5px margin on each side.
+    */
+   
+    this.getComputeNodeSize = lodash.memoize((instances) => {
+      const width = (serviceTopologyConfig.instance.margin * 3) + (serviceTopologyConfig.instance.width *2);
+
+      const rows = Math.round(instances.length / 2);
+
+      const labelSpace = this.getComputeNodeLabelSize();
+
+      const height = (serviceTopologyConfig.instance.height * rows) + (serviceTopologyConfig.instance.margin * (rows + 1)) + labelSpace;
+
+      return [width, height];
+    });
+
+    /**
+    * Give a list on Compute Node should calculate the Rack Size.
+    * Compute nodes are placed in a single column with 5px margin on each side.
+    */
+    this.getRackSize = (nodes) => {
+
+      let width = 0;
+      let height = serviceTopologyConfig.computeNode.margin;
+
+      lodash.forEach(nodes, (node) => {
+        let [nodeWidth, nodeHeight] = this.getComputeNodeSize(node.instances);
+
+        width = nodeWidth + (serviceTopologyConfig.computeNode.margin * 2);
+        height += (nodeHeight + serviceTopologyConfig.computeNode.margin);
+      });
+
+      return [width, height];
+    };
+
+    /**
+    * Given an instance index, return the coordinates
+    */
+   
+    this.getInstancePosition = (position) => {
+      const row = Math.floor(position / 2);
+      const column = (position % 2) ? 1 : 0;
+
+      // add ComputeNode label size
+      const labelSpace = this.getComputeNodeLabelSize();
+
+      // x = margin + (width * column) + ( maring * column)
+      const x = serviceTopologyConfig.instance.margin + (serviceTopologyConfig.instance.width * column) + (serviceTopologyConfig.instance.margin * column);
+
+      // y = label + margin + (height * row) + ( maring * row)
+      const y = labelSpace + serviceTopologyConfig.instance.margin + (serviceTopologyConfig.instance.height * row) + (serviceTopologyConfig.instance.margin * row);
+      return [x, y];
+    };
+
+    /**
+    * Given an Compute Node index, return the coordinates
+    */
+
+    this.getComputeNodePosition = (nodes, position) => {
+
+      const x = serviceTopologyConfig.computeNode.margin;
+
+      let previousElEight = lodash.reduce(nodes.slice(0, position), (val, node) => {
+        return val + this.getComputeNodeSize(node.instances)[1]
+      }, 0);
+
+      const y =
+        serviceTopologyConfig.computeNode.margin
+        + (serviceTopologyConfig.computeNode.margin * position)
+        + previousElEight;
+
+      return [x, y];
+    };
+
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/rest_services.js b/views/ngXosViews/diagnostic/src/js/rest_services.js
new file mode 100644
index 0000000..f49df1c
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/rest_services.js
@@ -0,0 +1,445 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('Services', function($resource){
+    return $resource('/xos/services/:id', {id: '@id'});
+  })
+  .service('Tenant', function($resource){
+    return $resource('/xos/tenants', {id: '@id'}, {
+      queryVsgInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: (res) => {
+
+            // NOTE
+            // Note that VCPETenant is now VSGTenant.
+
+            let instances = [];
+
+            angular.forEach(res.data, (tenant) => {
+              let info = JSON.parse(tenant.service_specific_attribute);
+              if(info && info.instance_id){
+                instances.push(info.instance_id);
+              }
+            });
+
+            return instances;
+          }
+        }
+      },
+      getSubscriberTag: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: (res) => {
+            // NOTE we should receive only one vOLT tenant here
+            return JSON.parse(res.data[0].service_specific_attribute);
+          }
+        }
+      }
+    });
+  })
+  .service('Ceilometer', function($http, $q, Instances) {
+
+    /**
+    * Get stats for a single instance
+    */
+    this.getInstanceStats = (instanceUuid) => {
+      let deferred = $q.defer();
+
+      $http.get('/xoslib/xos-instance-statistics', {params: {'instance-uuid': instanceUuid}})
+      .then((res) => {
+        deferred.resolve(res.data);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      })
+
+      return deferred.promise;
+    };
+
+    /**
+    * Collect stats for an array of instances
+    */
+    this.getInstancesStats = (instances) => {
+      let deferred = $q.defer();
+      let instancePromises = [];
+      let instanceList = [];
+
+      // retrieve instance details
+      instances.forEach((instanceId) => {
+        instancePromises.push(Instances.get({id: instanceId}).$promise);
+      });
+
+      // get all instance data
+      $q.all(instancePromises)
+      .then((_instanceList) => {
+        instanceList = _instanceList;
+        let promises = [];
+        // foreach instance query stats
+        instanceList.forEach((instance) => {
+          promises.push(this.getInstanceStats(instance.instance_uuid));
+        });
+        return $q.all(promises);
+      })
+      .then(stats => {
+        // augment instance with stats information
+        instanceList.map((instance, i) => {
+          instance.stats = stats[i];
+        });
+        deferred.resolve(instanceList);
+      })
+      .catch(deferred.reject);
+
+      return deferred.promise;
+    };
+
+    this.getContainerStats = (containerName) => {
+      const deferred = $q.defer();
+
+      let res = {};
+
+      $http.get('/xoslib/meterstatistics', {params: {'resource': containerName}})
+      .then((containerStats) => {
+        res.stats = containerStats.data;
+        return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth0`}})
+      })
+      .then((portStats) => {
+        res.port = {
+          eth0: portStats.data
+        };
+        return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth1`}})
+      })
+      .then((portStats) => {
+        res.port.eth1 = portStats.data;
+        deferred.resolve(res);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      })
+
+      return deferred.promise;
+    }
+  })
+  .service('Slice', function($resource){
+    return $resource('/xos/slices', {id: '@id'});
+  })
+  .service('Instances', function($resource){
+    return $resource('/xos/instances/:id', {id: '@id'});
+  })
+  .service('Node', function($resource, $q, Instances){
+    return $resource('/xos/nodes', {id: '@id'}, {
+      queryWithInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function(res){
+
+            // TODO update the API to include instances in nodes
+            // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
+
+            const deferred = $q.defer();
+
+            let requests = [];
+
+            angular.forEach(res.data, (node) => {
+              requests.push(Instances.query({node: node.id}).$promise);
+            })
+
+            $q.all(requests)
+            .then((list) => {
+              res.data.map((node, i) => {
+                node.instances = list[i];
+                return node;
+              });
+              deferred.resolve(res.data);
+            })
+
+            return deferred.promise;
+          }
+        }
+      }
+    });
+  })
+  .service('Subscribers', function($resource, $q, SubscriberDevice){
+    return $resource('/xos/subscribers/:id', {id: '@id'}, {
+      queryWithDevices: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function(res){
+
+            /**
+            * For each subscriber retrieve devices and append them
+            */
+
+            let deferred = $q.defer();
+
+            let requests = [];
+
+            angular.forEach(res.data, (subscriber) => {
+              requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
+            })
+
+            $q.all(requests)
+            .then((list) => {
+
+              // adding devices
+
+              res.data.map((subscriber, i) => {
+                subscriber.devices = list[i];
+                subscriber.type = 'subscriber';
+
+                subscriber.devices.map(d => d.type = 'device')
+
+                return subscriber;
+              });
+
+              // faking to have 2 subscriber
+              // res.data.push(angular.copy(res.data[0]));
+
+              deferred.resolve(res.data);
+            })
+
+            return deferred.promise;
+          }
+        }
+      },
+      getWithDevices: {
+        method: 'GET',
+        isArray: false,
+        interceptor: {
+          response: (res) => {
+            let d = $q.defer();
+
+            SubscriberDevice.query({id: res.data.id}).$promise
+            .then(devices => {
+              devices.map(d => d.type = 'device');
+              res.data.devices = devices;
+              res.data.type = 'subscriber';
+              d.resolve(res.data);
+            })
+            .catch(err => {
+              d.reject(err);
+            });
+
+            return d.promise;
+          }
+        }
+      }
+    });
+  })
+  .service('SubscriberDevice', function($resource){
+    return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
+  })
+  .service('ServiceRelation', function($q, lodash, Services, Tenant, Slice, Instances){
+
+    // 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
+    };
+
+    // find all the relation defined for a given root
+    const findLevelRelation = (tenants, rootId) => {
+      return lodash.filter(tenants, service => {
+        return service.subscriber_service === rootId;
+      });
+    };
+
+    const findSpecificInformation = (tenants, rootId) => {
+      var tenants = lodash.filter(tenants, service => {
+        return service.provider_service === rootId && service.subscriber_tenant;
+      });
+
+      var info;
+
+      tenants.forEach((tenant) => {
+        if(tenant.service_specific_attribute){
+          info = JSON.parse(tenant.service_specific_attribute);
+        }
+      });
+
+      return info;
+    };
+
+    // find all the service defined by a given array of relations
+    const findLevelServices = (relations, services) => {
+      const levelServices = [];
+      lodash.forEach(relations, (tenant) => {
+        var service = lodash.find(services, {id: tenant.provider_service});
+        levelServices.push(service);
+      });
+      return levelServices;
+    };
+
+    const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
+
+      // build an array of unlinked services
+      // these are the services that should still placed in the tree
+      var unlinkedServices = lodash.difference(services, [rootService]);
+
+      // find all relations relative to this rootElement
+      const levelRelation = findLevelRelation(tenants, rootService.id);
+      // find all items related to rootElement
+      const levelServices = findLevelServices(levelRelation, services);
+
+      // remove this item from the list (performance
+      unlinkedServices = lodash.difference(unlinkedServices, levelServices);
+
+      rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
+
+      const tree = {
+        name: rootService.humanReadableName,
+        parent: parentName,
+        type: 'service',
+        service: rootService,
+        tenant: rootTenant,
+        children: []
+      };
+
+      lodash.forEach(levelServices, (service) => {
+        let tenant = lodash.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
+        tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
+      });
+
+      // if it is the last element append internet
+      if(tree.children.length === 0){
+        tree.children.push({
+          name: 'Router',
+          type: 'router',
+          children: []
+        });
+      }
+
+      return tree;
+    };
+
+    const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
+
+      // find the root service
+      // it is the one attached to subsriber_root
+      // as now we have only one root so this can work
+      const rootTenant = lodash.find(tenants, {subscriber_root: subscriber.id});
+      const rootService = lodash.find(services, {id: rootTenant.provider_service});
+
+      const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
+
+      return {
+        name: subscriber.name,
+        parent: null,
+        type: 'subscriber',
+        children: [serviceTree]
+      };
+
+    };
+
+    // applying domain knowledge to build the global service tree
+    const buildServiceTree = (services, tenants) => {
+
+      // TODO refactor
+      const buildChild = (services, tenants, currentService) => {
+
+        const response = {
+          type: 'service',
+          name: currentService.humanReadableName,
+          service: currentService
+        };
+
+        let tenant = lodash.find(tenants, {subscriber_service: currentService.id});
+        if(tenant){
+          let next = lodash.find(services, {id: tenant.provider_service});
+          response.children = [buildChild(services, tenants, next)];
+        }
+        else {
+          response.children = [
+            {
+              name: 'Router',
+              type: 'router',
+              children: []
+            }
+          ]
+        }
+        delete currentService.id; // conflict with d3
+        return response;
+      }
+
+      let baseService = lodash.find(services, {id: 3});
+      
+      if(!angular.isDefined(baseService)){
+        console.error('Missing Base service!');
+        return;
+      }
+
+      const baseData = {
+        name: 'Subscriber',
+        type: 'subscriber',
+        parent: null,
+        children: [buildChild(services, tenants, baseService)]
+      };
+      return baseData;
+    };
+
+    const getBySubscriber = (subscriber) => {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenant.query().$promise;
+      })
+      .then((res) => {
+        tenants = res;
+        deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    };
+
+    const get = () => {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenant.query({kind: 'coarse'}).$promise;
+      })
+      .then((res) => {
+        tenants = res;
+        deferred.resolve(buildServiceTree(services, tenants));
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    }
+
+    // export APIs
+    return {
+      get: get,
+      buildServiceTree: buildServiceTree,
+      getBySubscriber: getBySubscriber,
+      buildLevel: buildLevel,
+      buildSubscriberServiceTree: buildSubscriberServiceTree,
+      findLevelRelation: findLevelRelation,
+      findLevelServices: findLevelServices,
+      depthOf: depthOf,
+      findSpecificInformation: findSpecificInformation
+    }
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopology.js b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
new file mode 100644
index 0000000..49e5d71
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
@@ -0,0 +1,81 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .directive('serviceTopology', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        serviceChain: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      template: '',
+      controller: function($element, $window, $scope, d3, serviceTopologyConfig, ServiceRelation, Slice, Instances, Subscribers, ServiceTopologyHelper){
+
+        const el = $element[0];
+
+        d3.select(window)
+        .on('resize', () => {
+          draw(this.serviceChain);
+        });
+
+        var root, svg;
+
+        const draw = (tree) => {
+
+          if(!tree){
+            console.error('Tree is missing');
+            return;
+          }
+
+          // TODO update instead clear and redraw
+
+          // clean
+          d3.select($element[0]).select('svg').remove();
+
+          const width = el.clientWidth - (serviceTopologyConfig.widthMargin * 2);
+          const height = el.clientHeight - (serviceTopologyConfig.heightMargin * 2);
+
+          const treeLayout = d3.layout.tree()
+            .size([height, width]);
+
+          svg = d3.select($element[0])
+            .append('svg')
+            .style('width', `${el.clientWidth}px`)
+            .style('height', `${el.clientHeight}px`)
+
+          const treeContainer = svg.append('g')
+            .attr('transform', `translate(${serviceTopologyConfig.widthMargin * 4},${serviceTopologyConfig.heightMargin})`);
+
+          root = tree;
+          root.x0 = height / 2;
+          root.y0 = width / 2;
+
+          // ServiceTopologyHelper.drawLegend(svg);
+          ServiceTopologyHelper.updateTree(treeContainer, treeLayout, root);
+        };
+
+        this.getInstances = (slice) => {
+          Instances.query({slice: slice.id}).$promise
+          .then((instances) => {
+            this.selectedSlice = slice;
+            this.instances = instances;
+          })
+          .catch(e => {
+            this.errors = e;
+            throw new Error(e);
+          })
+        };
+        
+        $scope.$watch(() => this.serviceChain, (chain) => {
+          console.log(chain);
+          if(angular.isDefined(chain)){
+            draw(chain);
+          }
+        });
+      }
+    }
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
new file mode 100644
index 0000000..1d53d72
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
@@ -0,0 +1,246 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('ServiceTopologyHelper', function($rootScope, $window, $log, lodash, ServiceRelation, serviceTopologyConfig, d3){
+
+    // NOTE not used anymore
+    const drawLegend = (svg) => {
+      const legendContainer = svg.append('g')
+        .attr({
+          class: 'legend'
+        });
+
+      legendContainer.append('rect')
+      .attr({
+        transform: d => `translate(10, 80)`,
+        width: 100,
+        height: 100
+      });
+
+      // service
+      const service = legendContainer.append('g')
+      .attr({
+        class: 'node service'
+      });
+
+      service.append('circle')
+      .attr({
+        r: serviceTopologyConfig.circle.radius,
+        transform: d => `translate(30, 100)`
+      });
+
+      service.append('text')
+      .attr({
+        transform: d => `translate(45, 100)`,
+        dy: '.35em'
+      })
+      .text('Service')
+        .style('fill-opacity', 1);
+
+      // slice
+      const slice = legendContainer.append('g')
+        .attr({
+          class: 'node slice'
+        });
+
+      slice.append('rect')
+        .attr({
+          width: 20,
+          height: 20,
+          x: -10,
+          y: -10,
+          transform: d => `translate(30, 130)`
+        });
+
+      slice.append('text')
+        .attr({
+          transform: d => `translate(45, 130)`,
+          dy: '.35em'
+        })
+        .text('Slices')
+        .style('fill-opacity', 1);
+
+      // instance
+      const instance = legendContainer.append('g')
+        .attr({
+          class: 'node instance'
+        });
+
+      instance.append('rect')
+        .attr({
+          width: 20,
+          height: 20,
+          x: -10,
+          y: -10,
+          transform: d => `translate(30, 160)`
+        });
+
+      instance.append('text')
+        .attr({
+          transform: d => `translate(45, 160)`,
+          dy: '.35em'
+        })
+        .text('Instances')
+        .style('fill-opacity', 1);
+    };
+
+    var _svg, _layout, _source;
+
+    var i = 0;
+
+    // given a canvas, a layout and a data source, draw a tree layout
+    const updateTree = (svg, layout, source) => {
+
+      //cache data
+      _svg = svg;
+      _layout = layout;
+      _source = source;
+
+      const maxDepth = ServiceRelation.depthOf(source);
+
+      const diagonal = d3.svg.diagonal()
+        .projection(d => [d.y, d.x]);
+
+      // Compute the new tree layout.
+      var nodes = layout.nodes(source).reverse(),
+        links = layout.links(nodes);
+
+      // Normalize for fixed-depth.
+      nodes.forEach(function(d) {
+        // position the child node horizontally
+        const step = (($window.innerWidth - (serviceTopologyConfig.widthMargin * 2)) / maxDepth);
+        d.y = d.depth * step;
+      });
+
+      // 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: d => {
+            return `node ${d.type}`
+          },
+          transform: d => (d.x && d.y) ? `translate(${d.y}, ${d.x})` : `translate(${source.y0}, ${source.x0})`
+        });
+
+      const subscriberNodes = nodeEnter.filter('.subscriber');
+      const internetNodes = nodeEnter.filter('.router');
+      const serviceNodes = nodeEnter.filter('.service');
+
+      subscriberNodes.append('rect')
+        .attr(serviceTopologyConfig.square);
+
+      internetNodes.append('rect')
+        .attr(serviceTopologyConfig.square);
+
+      serviceNodes.append('circle')
+        .attr('r', 1e-6)
+        .style('fill', d => d._children ? 'lightsteelblue' : '#fff')
+        .on('click', serviceClick);
+
+      nodeEnter.append('text')
+        .attr({
+          x: d => d.children ? -serviceTopologyConfig.circle.selectedRadius -3 : serviceTopologyConfig.circle.selectedRadius + 3,
+          dy: '.35em',
+          transform: d => {
+            if (d.children && d.parent){
+              if(d.parent.x < d.x){
+                return 'rotate(-30)';
+              }
+              return 'rotate(30)';
+            }
+          },
+          'text-anchor': d => d.children ? 'end' : 'start'
+        })
+        .text(d => d.name)
+        .style('fill-opacity', 1e-6);
+
+      // Transition nodes to their new position.
+      var nodeUpdate = node.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          'transform': d => `translate(${d.y},${d.x})`
+        });
+
+      nodeUpdate.select('circle')
+        .attr('r', d => {
+          return d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius
+        })
+        .style('fill', d => d.selected ? 'lightsteelblue' : '#fff');
+
+      nodeUpdate.select('text')
+        .style('fill-opacity', 1);
+
+      // Transition exiting nodes to the parent's new position.
+      var nodeExit = node.exit().transition()
+        .duration(serviceTopologyConfig.duration)
+        .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', d => `link ${d.target.type} ${d.target.active ? '' : 'active'}`)
+        .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(serviceTopologyConfig.duration)
+        .attr('d', diagonal);
+
+      // Transition exiting nodes to the parent's new position.
+      link.exit().transition()
+        .duration(serviceTopologyConfig.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;
+      });
+    };
+
+    const serviceClick = function(d) {
+
+      // if was selected
+      if(d.selected){
+        d.selected = !d.selected;
+        $rootScope.$emit('instance.detail.hide', {});
+        return updateTree(_svg, _layout, _source);
+      }
+      
+      $rootScope.$emit('instance.detail', {name: d.name, service: d.service, tenant: d.tenant});
+
+      // unselect all
+      _svg.selectAll('circle')
+      .each(d => d.selected = false);
+
+      // toggling selected status
+      d.selected = !d.selected;
+
+      updateTree(_svg, _layout, _source);
+    };
+
+    this.updateTree = updateTree;
+    this.drawLegend = drawLegend;
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/subscriber-modal.js b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
new file mode 100644
index 0000000..0620277
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
@@ -0,0 +1,27 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('subscriberModal', function(){
+    return {
+      scope: {
+        subscribers: '=',
+        open: '='
+      },
+      bindToController: true,
+      restrict: 'E',
+      templateUrl: 'templates/subscriber-modal.tpl.html',
+      controllerAs: 'vm',
+      controller: function($rootScope){
+
+        this.close = () => {
+          this.open = false;
+        };
+
+        this.select = (subscriber) => {
+          $rootScope.$emit('subscriber.selected', subscriber);
+          this.close();
+        };
+      }
+    };
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
new file mode 100644
index 0000000..172b9f7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
@@ -0,0 +1,30 @@
+<div class="container-fluid">
+  <div ng-hide="vm.error && vm.loader">
+    <div class="onethird-height">
+      <service-topology service-chain="vm.serviceChain"></service-topology>
+    </div>
+    <div class="twothird-height">
+      <!-- <div class="panel panel-primary subscriber-select">
+        <div class="panel-heading">Select a subscriber:</div>
+        <div class="panel-body">
+          <select class="form-control" ng-options="s as s.name for s in vm.subscribers" ng-model="vm.selectedSubscriber">
+            <option value="">Select a subscriber...</option>
+          </select>
+        </div>
+      </div> -->
+      <logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>
+    </div>
+  </div>
+  <div class="row" ng-show="vm.error">
+    <div class="col-xs-12">
+      <div class="alert alert-danger">
+        {{vm.error}}
+      </div>
+    </div>
+  </div>
+  <div class="row" ng-show="vm.loader">
+    <div class="col-xs-12">
+      <div class="loader">Loading</div>
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html b/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html
new file mode 100644
index 0000000..0cff927
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html
@@ -0,0 +1,23 @@
+<subscriber-modal open="vm.subscriberModal" subscribers="vm.subscribers"></subscriber-modal>
+<div class="instances-stats animate" ng-hide="vm.hideInstanceStats">
+  <div class="row">
+    <div class="col-sm-3 col-sm-offset-8">
+      <div class="panel panel-primary" ng-repeat="instance in vm.selectedInstances">
+        <div class="panel-heading">
+          {{instance.humanReadableName}}
+        </div>
+          <ul class="list-group">
+            <li class="list-group-item">Backend Status: {{instance.backend_status}}</li>
+            <li class="list-group-item">IP Address: {{instance.ip}}</li>
+          </ul>
+          <ul class="list-group">
+            <li class="list-group-item" ng-repeat="stat in instance.stats">
+              <span class="badge">{{stat.value}}</span>
+              {{stat.meter}}
+            </li>
+          </ul>
+        </div>
+      </div>  
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/subscriber-modal.tpl.html b/views/ngXosViews/diagnostic/src/templates/subscriber-modal.tpl.html
new file mode 100644
index 0000000..7672a29
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/subscriber-modal.tpl.html
@@ -0,0 +1,17 @@
+<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">
+  <div class="modal-dialog modal-sm">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+        <h4 class="modal-title">Select a subscriber:</h4>
+      </div>
+      <div class="modal-body">
+        <select class="form-control" ng-options="s as s.humanReadableName for s in vm.subscribers" ng-model="vm.selected"></select>
+      </div>
+      <div class="modal-footer">
+        <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        <button ng-click="vm.select(vm.selected)" type="button" class="btn btn-primary">Select</button>
+      </div>
+    </div><!-- /.modal-content -->
+  </div><!-- /.modal-dialog -->
+</div><!-- /.modal -->
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.bowerrc b/views/ngXosViews/mcordTopology/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.eslintrc b/views/ngXosViews/mcordTopology/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.gitignore b/views/ngXosViews/mcordTopology/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/bower.json b/views/ngXosViews/mcordTopology/bower.json
new file mode 100644
index 0000000..cb9b543
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/bower.json
@@ -0,0 +1,30 @@
+{
+  "name": "xos-mcordTopology",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The mcordTopology view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "d3": "~3.5.16"
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-resource": "1.4.7",
+    "ng-lodash": "0.3.0",
+    "bootstrap-css": "2.3.2"
+  }
+}
diff --git a/views/ngXosViews/mcordTopology/env/default.js b/views/ngXosViews/mcordTopology/env/default.js
new file mode 100644
index 0000000..df86216
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/env/default.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://clnode067.clemson.cloudlab.us:9999/',
+  xoscsrftoken: 'Pkq9PqoAsaMvrEiFAgxfw47IxTOtd0Y5',
+  xossessionid: 'qa1t49qeecdehofjkndqvxik71iwzfvf'
+};
diff --git a/views/ngXosViews/mcordTopology/env/mock.js b/views/ngXosViews/mcordTopology/env/mock.js
new file mode 100644
index 0000000..610ad78
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/env/mock.js
@@ -0,0 +1,5 @@
+module.exports = {
+  host: 'http://localhost:4000',
+  xoscsrftoken: 'Pkq9PqoAsaMvrEiFAgxfw47IxTOtd0Y5',
+  xossessionid: 'qa1t49qeecdehofjkndqvxik71iwzfvf'
+};
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/gulp/build.js b/views/ngXosViews/mcordTopology/gulp/build.js
new file mode 100644
index 0000000..80ba4be
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulp/build.js
@@ -0,0 +1,147 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+var TEMPLATE_FOOTER = `
+angular.module('xos.mcordTopology').run(function($location){$location.path('/')});
+angular.bootstrap(angular.element('#xosMcordTopology'), ['xos.mcordTopology']);`;
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [options.dashboards + 'xosMcordTopology.html'],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  gulp.task('copyCss', ['css'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosMcordTopology.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosMcordTopology.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    // .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.mcordTopology',
+        root: 'templates/',
+        templateFooter: TEMPLATE_FOOTER
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', ['clean'], function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n.*)*\n<!-- endbower --><!-- endcss -->/, ''))
+      .pipe(replace(/<!-- bower:js -->(\n.*)*\n<!-- endbower --><!-- endjs -->/, ''))
+      .pipe(replace(/ng-app=".*"\s/, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosMcordTopologyVendor.js',
+            options.static + 'js/xosMcordTopology.js',
+            options.static + 'css/xosMcordTopology.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosMcordTopology.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosMcordTopologyVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'templates',
+      'copyCss',
+      'babel',
+      'scripts',
+      'wiredep',
+      'copyHtml'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/gulp/server.js b/views/ngXosViews/mcordTopology/gulp/server.js
new file mode 100644
index 0000000..7605294
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulp/server.js
@@ -0,0 +1,146 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+
+const environment = process.env.NODE_ENV;
+
+if (environment){
+  var conf = require(`../env/${environment}.js`);
+}
+else{
+  var conf = require('../env/default.js')
+}
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host || 'http://0.0.0.0:9999'
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  // open in browser with sync and proxy to 0.0.0.0
+  gulp.task('browser', function() {
+    browserSync.init({
+      // reloadDelay: 500,
+      // logLevel: 'debug',
+      // logConnections: true,
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/api': options.api,
+          '/xosHelpers/src': options.helpers
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/xos/') !== -1 ||
+            req.url.indexOf('/xoslib/') !== -1 ||
+            req.url.indexOf('/hpcapi/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.api + '*.js',
+            options.helpers + '**/*.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src(options.src + 'css/*.css'),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/mcordTopology/gulpfile.js b/views/ngXosViews/mcordTopology/gulpfile.js
new file mode 100644
index 0000000..a3523ee
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulpfile.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../ngXosLib/xosHelpers/src/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/mcordTopology/karma.conf.js b/views/ngXosViews/mcordTopology/karma.conf.js
new file mode 100644
index 0000000..83d3f63
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../static/js/xosApi.js',
+      '../../static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/mcordTopology/mocks/data/instances.json b/views/ngXosViews/mcordTopology/mocks/data/instances.json
new file mode 100644
index 0000000..572c775
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/mocks/data/instances.json
@@ -0,0 +1,56 @@
+[
+  {
+    "id": 1,
+    "humanReadableName": "BBU_service_instance-1",
+    "instance_id": "instance-00000001", 
+    "instance_uuid": "42b75cb7-7205-4a68-9100-b2c1e3ea69b5", 
+    "name": "BBU_service_instance-1", 
+    "instance_name": "mysite_BBU-1", 
+    "ip": "130.127.133.91"
+  },
+  {
+    "id": 2,
+    "humanReadableName": "BBU_service_instance-2",
+    "instance_id": "instance-00000002", 
+    "instance_uuid": "42b75cb7-7205-4a68-9200-b2c2e3ea69b5", 
+    "name": "BBU_service_instance-2", 
+    "instance_name": "mysite_BBU-2", 
+    "ip": "130.127.133.92"
+  },
+  {
+    "id": 5,
+    "humanReadableName": "vsg_service_instance-4",
+    "instance_id": "instance-00000004", 
+    "instance_uuid": "44b75cb7-7405-4a68-9400-b4c4e3ea69b5", 
+    "name": "vsg_service_instance-4", 
+    "instance_name": "mysite_vsg-4", 
+    "ip": "130.127.133.94"
+  },
+  {
+    "id": 6,
+    "humanReadableName": "MME_service_instance-4",
+    "instance_id": "instance-00000004", 
+    "instance_uuid": "44b75cb7-7405-4a68-9400-b4c4e3ea69b5", 
+    "name": "MME_service_instance-4", 
+    "instance_name": "mysite_MME-4", 
+    "ip": "130.127.133.94"
+  },
+  {
+    "id": 7,
+    "humanReadableName": "SGW_service_instance-4",
+    "instance_id": "instance-00000004", 
+    "instance_uuid": "44b75cb7-7405-4a68-9400-b4c4e3ea69b5", 
+    "name": "SGW_service_instance-4", 
+    "instance_name": "mysite_SGW-4", 
+    "ip": "130.127.133.94"
+  },
+  {
+    "id": 8,
+    "humanReadableName": "PGW_service_instance-4",
+    "instance_id": "instance-00000004", 
+    "instance_uuid": "44b75cb7-7405-4a68-9400-b4c4e3ea69b5", 
+    "name": "PGW_service_instance-4", 
+    "instance_name": "mysite_PGW-4", 
+    "ip": "130.127.133.94"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/mocks/mcord.conf.json b/views/ngXosViews/mcordTopology/mocks/mcord.conf.json
new file mode 100644
index 0000000..7246775
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/mocks/mcord.conf.json
@@ -0,0 +1,8 @@
+[
+  {
+    "url": "instances",
+    "base": "xos/",
+    "methods": ["GET", "POST"],
+    "param": "id"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/package.json b/views/ngXosViews/mcordTopology/package.json
new file mode 100644
index 0000000..9826895
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/package.json
@@ -0,0 +1,53 @@
+{
+  "name": "xos-mcordTopology",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "lint": "eslint src/js/",
+    "mocks": "easy-mocker -c ./mocks/mcord.conf.json -d ./mocks/data",
+    "dev": "NODE_ENV=mock gulp serve"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "lodash": "^3.10.1",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/mcordTopology/spec/sample.test.js b/views/ngXosViews/mcordTopology/spec/sample.test.js
new file mode 100644
index 0000000..ecc17a0
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/spec/sample.test.js
@@ -0,0 +1,37 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.mcordTopology'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/xos/users/?no_hyperlinks=1').respond([
+      {
+        email: 'teo@onlab.us',
+        firstname: 'Matteo',
+        lastname: 'Scandolo' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should load 1 users', () => {
+    httpBackend.flush();
+    expect(isolatedScope.users.length).toBe(1);
+    expect(isolatedScope.users[0].email).toEqual('teo@onlab.us');
+    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
+    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
+  });
+
+});
\ No newline at end of file
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..df22bfe
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/mcord.css
@@ -0,0 +1,71 @@
+#xosMcordTopology {
+  height: 700px;
+}
+
+[ui-view],
+m-cord-topology{
+  width: 100%;
+  height: 100%;
+  display: block;
+}
+
+line {
+  stroke: blue;
+  stroke-width: 1;
+}
+
+line.big{
+  stroke-width: 2;
+}
+
+circle,
+rect {
+  fill: #fff;
+  stroke-width: 1; 
+}
+
+.fabric {
+  stroke: none;
+  fill: #123456;
+  fill-rule: evenodd;
+}
+
+.fabric-container {
+  fill: transparent;
+  stroke: #000;
+  stroke-width: 1;
+}
+
+.bbu {
+  stroke: black;
+  fill: #FF7F0E;
+}
+
+.rru {
+  stroke: #000;
+  fill: #FFBB78;
+}
+
+.rru.antenna {
+  stroke: #000;
+  fill: brown;
+}
+
+.rru-shadow {
+  fill: #FFBB78;
+  opacity: .4
+}
+
+.MME, .SGW, .PGW {
+  fill: purple;
+  stroke: #000;
+}
+
+.bbu text, 
+.MME text,
+.SGW text,
+.PGW text {
+  font-size: 10px;
+  stroke-width: 0;
+  fill: #fff;
+}
\ 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..691a869
--- /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/node_drawer.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/mcordTopology/src/js/main.js b/views/ngXosViews/mcordTopology/src/js/main.js
new file mode 100644
index 0000000..caf7b65
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/main.js
@@ -0,0 +1,300 @@
+'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, $interval, XosApi, lodash, TopologyElements, NodeDrawer){
+
+      const el = $element[0];
+
+      let nodes = [];
+      let 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
+      const getData = () => {
+
+        d3.select('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+
+        nodes = TopologyElements.nodes;
+        links = TopologyElements.links;
+
+        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`);
+
+      const linkContainer = svg.append('g')
+        .attr({
+          class: 'link-container'
+        });
+
+      const nodeContainer = svg.append('g')
+        .attr({
+          class: 'node-container'
+        });
+
+      // replace human readable ids with d3 ids
+      // NOTE now ids are not manatined on update...
+      const buildLinks = (links, nodes) => {
+        return links.map((l) => {
+
+
+          let source = lodash.findIndex(nodes, {id: l.source});
+          let target = lodash.findIndex(nodes, {id: l.target});
+          // console.log(`link-${source}-${target}`, source, target);
+          return {
+            source: source,
+            target: target,
+            value: 1,
+            id: `link-${source}-${target}`,
+            type: l.source.indexOf('fabric') >= 0 ? 'big':'small'
+          };
+
+        });
+      };
+
+      // 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);
+      }
+
+      let hStep, vStep;
+
+      hStep = el.clientWidth / 3;
+      vStep = el.clientHeight / 5;
+
+      const draw = (svg, nodes, links) => {
+
+        hStep = el.clientWidth / 3;
+        vStep = el.clientHeight / 5;
+
+        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();
+
+
+        const linkContainer = d3.select('.link-container');
+        const nodeContainer = d3.select('.node-container');
+
+        NodeDrawer.drawFabricBox(nodeContainer, hStep, vStep);
+
+        // draw links
+        var link = linkContainer.selectAll('.link')
+          .data(links, d => d.id);
+        
+        link.enter().append('line')
+          .attr({
+            // class: 'link',
+            id: d => d.id,
+            opacity: 0,
+            class: d => `link ${d.type}`
+          })
+          .transition()
+          .duration(1000)
+          // .delay((d, i) => 50 * i)
+          .attr({
+            opacity: 1
+          });
+
+        link.exit()
+        .remove();
+
+        //draw nodes
+        var node = nodeContainer.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} node`,
+            transform: d => `translate(${d.x}, ${d.y})`
+          });
+
+        // draw nodes
+        NodeDrawer.drawBbus(enter.filter('.bbu'))
+        NodeDrawer.drawRrus(enter.filter('.rru'))
+        NodeDrawer.drawFabric(enter.filter('.fabric'))
+        NodeDrawer.drawOthers(enter.filter(d => {
+          return (
+            d.type  === 'MME' ||
+            d.type === 'SGW' ||
+            d.type === 'PGW'
+          )
+        }));
+
+        // remove nodes
+        var exit = node.exit();
+
+        NodeDrawer.removeElements(exit);
+
+        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})`);
+        });
+      };
+      
+      $interval(() => {
+        getData();
+      }, 5000);
+      getData();
+
+      
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/node_drawer.js b/views/ngXosViews/mcordTopology/src/js/node_drawer.js
new file mode 100644
index 0000000..14d85a7
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/node_drawer.js
@@ -0,0 +1,207 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.service('NodeDrawer', function(TopologyElements){
+
+  const duration = 500;
+
+  let isFabricDrawed = false;
+
+  this.drawFabricBox = (svg, hStep, vStep) => {
+
+    if(isFabricDrawed){
+      return;
+    }
+
+    let fabric = svg.append('g')
+    .attr({
+      transform: `translate(${hStep - 25}, ${vStep - 25})`
+    });
+
+    fabric.append('rect')
+      .attr({
+        width: hStep + 50,
+        height: vStep + 50,
+        class: 'fabric-container'
+      });
+
+    fabric.append('text')
+    .text('Fabric')
+    .attr({
+      'text-anchor': 'middle',
+      x: ((hStep + 50) / 2),
+      y: -10
+    });
+
+    isFabricDrawed = true;
+  };
+
+  this.drawBbus = (nodes) => {
+
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 15,
+    //     opacity: 1
+    //   });
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.bbu,
+        transform: `translate(-22, -22), scale(0.4)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'start',
+      y: 13,
+      x: -14,
+      opacity: 0
+    })
+    .text(d => `BBU ${d.name.substr(d.name.length - 1, 1)}`)
+    .transition()
+    .duration(duration * 2)
+    .attr({
+      opacity: 1
+    });
+  };
+
+  this.drawRrus = (nodes) => {
+
+    nodes.append('circle')
+      .attr({
+        class: d => `${d.type}-shadow`,
+        r: 0,
+        opacity: 0
+      })
+      .transition()
+      .duration(duration * 2)
+      // .delay((d, i) => i * (duration / 2))
+      .attr({
+        r: 40,
+        opacity: 1
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.rru,
+        transform: `translate(-22, -22), scale(0.4)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+  
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 10,
+    //     opacity: 1
+    //   });
+  };
+
+  this.drawFabric = (nodes) => {
+    nodes
+      .append('rect')
+      .attr({
+        width: 30,
+        height: 30,
+        x: -15,
+        y: -15
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => d.type,
+        opacity: 0,
+        d: () => TopologyElements.icons.switch,
+        transform: `translate(-22, -22), scale(0.4)`
+      })
+      .transition()
+      .duration(duration)
+      // .delay((d, i) => i * (duration / 2))
+      .attr({
+        opacity: 1
+      });
+  };
+
+  this.drawOthers = (nodes) => {
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 15,
+    //     opacity: 1
+    //   });
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.bbu,
+        transform: `translate(-22, -22), scale(0.4)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'start',
+      y: 13,
+      x: -12,
+      opacity: 0
+    })
+    .text(d => d.type)
+    .transition()
+    .duration(duration * 2)
+    .attr({
+      opacity: 1
+    });
+
+  };
+
+  this.removeElements = (nodes) => {
+    nodes
+    .transition()
+    .duration(duration)
+    .attr({
+      opacity: 0
+    })
+    .remove();
+  };
+});
\ 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..79adaa9
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/static.data.js
@@ -0,0 +1,65 @@
+'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'
+    }
+  ],
+  icons: {
+    bbu: `M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5v65a5,5,0,0,1-5,5zM14,22.5l11-11a10,3,0,0,1,10-2h40a10,3,0,0,1,10,2l11,11zM16,35a5,5,0,0,1,10,0a5,5,0,0,1-10,0z`,
+    switch: `M10,20a10,10,0,0,1,10-10h70a10,10,0,0,1,10,10v70a10,10,
+            0,0,1-10,10h-70a10,10,0,0,1-10-10zM60,26l12,0,0-8,18,13-18,13,0
+            -8-12,0zM60,60l12,0,0-8,18,13-18,13,0-8-12,0zM50,40l-12,0,0-8
+            -18,13,18,13,0-8,12,0zM50,74l-12,0,0-8-18,13,18,13,0-8,12,0z`,
+    rru: `M85,71.2c-8.9,10.5-29.6,8.7-45.3-3.5C23.9,55.4,19.8,37,28.6,26.5C29.9,38.6,71.5,69.9,85,71.2z M92.7,76.2M16.2,15 M69.5,100.7v-4c0-1.4-1.2-2.2-2.6-2.2H19.3c-1.4,0-2.8,0.7-2.8,2.2v3.9c0,0.7,0.8,1,1.5,1h50.3C69,101.5,69.5,101.3,69.5,100.7z M77.3,7.5l0,3.7c9,0.1,16.3,7.1,16.2,15.7l3.9,0C97.5,16.3,88.5,7.6,77.3,7.5z M77.6,14.7l0,2.5c5.3,0,9.7,4.2,9.6,9.3l2.6,0C89.9,20,84.4,14.7,77.6,14.7z M82.3,22.2c-1.3-1.2-2.9-1.9-4.7-1.9l0,1.2c1.4,0,2.8,0.6,3.8,1.5c1,1,1.6,2.3,1.6,3.7l1.3,0C84.3,25.1,83.6,23.4,82.3,22.2z M38.9,69.5l-5.1,23h16.5l-2.5-17.2C44.1,73.3,38.9,69.5,38.9,69.5zM58.1,54.1c13.7,10.1,26.5,16.8,29.2,13.7c2.7-3.1-5.6-13-19.3-24.4 M62.9,34.2 M62,37.9C47.7,27.3,33.7,20,31,23.1c-2.7,3.2,7,14.2,20.6,26 M73.9,25.7c-2.9,0.1-5.2,2.3-5.1,4.8c0,0.7,0.2,1.4,0.6,2l0,0L53.8,49.7l3.3,2.5L72.7,35l-0.4-0.3c0.6,0.2,1.3,0.3,1.9,0.3c2.9-0.1,5.2-2.3,5.1-4.9C79.3,27.6,76.8,25.6,73.9,25.7z`
+  }
+})
\ No newline at end of file
diff --git a/xos/configurations/common/make-nodes-yaml.sh b/xos/configurations/common/make-nodes-yaml.sh
index 74b8d0b..65e16bb 100644
--- a/xos/configurations/common/make-nodes-yaml.sh
+++ b/xos/configurations/common/make-nodes-yaml.sh
@@ -18,7 +18,7 @@
         type: tosca.nodes.Site
 EOF
 
-NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
 I=0
 for NODE in $NODES; do
     echo $NODE
diff --git a/xos/configurations/common/xos_common_config b/xos/configurations/common/xos_common_config
index f7b335e..1b83323 100644
--- a/xos/configurations/common/xos_common_config
+++ b/xos/configurations/common/xos_common_config
@@ -39,8 +39,9 @@
 logfile=/var/log/xos_backend.log
 
 [gui]
-disable_minidashboard=True
-branding_name=Open Cloud
-branding_icon=/static/logo.png
-branding_favicon=/static/favicon.png
-branding_bg=/static/bg.jpg
+branding_name=M-CORD
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/mcord-bg2.jpg
+service_view_class=core.views.mCordServiceGrid.ServiceGridView
+
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index 1be4a80..606f106 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -1,12 +1,18 @@
 .PHONY: xos
-xos: nodes.yaml images.yaml vtn_network_cfg_json
+xos: nodes.yaml images.yaml vtn_network_cfg_json virtualbng_json
 	sudo docker-compose up -d
 	../common/wait_for_xos_port.sh 80
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/setup.yaml
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
+
+vtn:
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord/vtn.yaml
+
+cord:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
 
 nodes.yaml:
 	export SETUPDIR=.; bash ../common/make-nodes-yaml.sh
@@ -14,6 +20,9 @@
 images.yaml:
 	export SETUPDIR=.; bash ../common/make-images-yaml.sh
 
+virtualbng_json:
+	export SETUPDIR=.; bash ./make-virtualbng-json.sh
+
 vtn_network_cfg_json:
 	export SETUPDIR=.; bash ./make-vtn-networkconfig-json.sh
 
diff --git a/xos/configurations/cord-pod/NOTES.txt b/xos/configurations/cord-pod/NOTES.txt
index d0ecf36..d832f2b 100644
--- a/xos/configurations/cord-pod/NOTES.txt
+++ b/xos/configurations/cord-pod/NOTES.txt
@@ -12,27 +12,26 @@
   - mgmtbr on head nodes
   - dnsmasq on head1 using cord config file
 * Install OpenStack using the openstack-cluster-install repo
-  TO ADD:
-  - Create XOS VM
-  - Install git, make, OpenStack clients
-  - Check out XOS inside VM
-  - Copy admin-openrc.sh and id_rsa* to correct location
-* Add trusty-server-multi-nic image to OpenStack
 
 VTN
-* Install Docker on the head node
-* Edit /etc/default/docker so that it points to mgmtbr
-* Create onos-cord Docker container
-  # docker ...
+* onos-cord VM is created by openstack-cluster-install
+* Bring up ONOS
+  # cd cord; docker-compose up -d
+* On each compute node it's necessary perform a few manual steps (FIX ME)
+  - Disable neutron-plugin-openvswitch-agent. As root:
+    # service neutron-plugin-openvswitch-agent stop
+    # echo manual > /etc/init/neutron-plugin-openvswitch-agent.override
+  - Clean up OVS: delete br-int and any other bridges
+  - Listen for connections from VTN:
+    # ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6641
 
 XOS
-* Create xos Docker containers attached to mgmtbr
-  # docker ...
+* xos VM is created by openstack-cluster-install
+  - requirements listed above should already be satisfied by install
+* cd xos/xos/configurations/cord-pod
 * Bring up XOS cord-pod configuration
-
-
-
-
-
-Test VTN
-* Try to create a network: neutron net-create testnet
+  # make
+  # make vtn
+  # make cord
+* Login to XOS at http://xos
+  - padmin@vicci.org / letmein
diff --git a/xos/configurations/cord-pod/README.md b/xos/configurations/cord-pod/README.md
index 0fcdb13..1824ab6 100644
--- a/xos/configurations/cord-pod/README.md
+++ b/xos/configurations/cord-pod/README.md
@@ -1,77 +1,79 @@
-# XOS Docker Images
+# XOS Configuration for CORD development POD
 
 ## Introduction
 
- XOS is comprised of 3 core services:
+This directory holds files that are used to configure a development POD for
+CORD.  For more information on the CORD project, check out
+[the CORD website](http://cord.onosproject.org/).
+
+XOS is composed of several core services:
 
   * A database backend (postgres)
   * A webserver front end (django)
-  * A synchronizer daemon that interacts with the openstack backend.
+  * A synchronizer daemon that interacts with the openstack backend
+  * A synchronizer for each configured XOS service
 
-We have created separate dockerfiles for each of these services, making it
-easier to build the services independently and also deploy and run them in
-isolated environments.
+Each service runs in a separate Docker container.  The containers are built
+automatically by [Docker Hub](https://hub.docker.com/u/xosproject/) using
+the HEAD of the XOS repository.
 
-#### Database Container
+## How to bring up CORD
 
-To build the database container:
+Installing a CORD POD requires three steps:
+ 1. Installing OpenStack on a cluster
+ 2. Setting up the ONOS VTN app and configuring OVS on the nova-compute nodes to be
+    controlled by VTN
+ 3. Bringing up XOS with the CORD services
 
+### Installing OpenStack
+
+Follow the instructions in the [README.md](https://github.com/open-cloud/openstack-cluster-setup/blob/master/README.md)
+file of the [open-cloud/openstack-cluster-setup](https://github.com/open-cloud/openstack-cluster-setup/)
+repository.
+
+### Setting up ONOS VTN
+
+The OpenStack installer above creates a VM called *onos-cord* on the head node.
+To bring up ONOS in this VM, log into the head node and run:
 ```
-$ cd postgresql; make build
+$ ssh ubuntu@onos-cord
+ubuntu@onos-cord:~$ cd cord; docker-compose up -d
 ```
 
-#### XOS Container
-
-To build the XOS webserver container:
-
+Currently it's also necessary to do some manual configuration on each compute
+node.  As root do the following:
+ 1. Disable neutron-plugin-openvswitch-agent, if running:
 ```
-$ cd xos; make build
+$ service neutron-plugin-openvswitch-agent stop
+$ echo manual > /etc/init/neutron-plugin-openvswitch-agent.override
+```
+ 2. Delete *br-int* and all other bridges from OVS
+ 3. Configure OVS to listen for connections from VTN:
+```
+$ ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6641
 ```
 
-#### Synchronizer Container
+### Bringing up XOS
 
-The Synchronizer shares many of the same dependencies as the XOS container. The
-synchronizer container takes advantage of this by building itself on top of the
-XOS image. This means you must build the XOS image before building the
-synchronizer image.  Assuming you have already built the XOS container,
-executing the following will build the Synchronizer container:
-
+The OpenStack installer above creates a VM called *xos* on the head node.
+To bring up XOS in this VM, first log into the head node and run:
 ```
-$ cd synchronizer; make build
+$ ssh ubuntu@xos
+ubuntu@xos:~$ cd xos/xos/configurations/cord-pod
 ```
 
-#### Solution Compose File
+Next, put the following files in this directory:
 
-[Docker Compose](https://docs.docker.com/compose/) is a tool for defining and
-running multi-container Docker applications. With Compose, you use a Compose
-file to configure your application’s services. Then, using a single command, you
-create, start, scale, and manage all the services from your configuration.
+ * *admin-openrc.sh*: Admin credentials for your OpenStack cloud
+ * *id_rsa[.pub]*: A keypair that will be used by the various services
+ * *node_key*: A private key that allows root login to the compute nodes
 
-Included is a compose file in *YAML* format with content defined by the [Docker
-Compose Format](https://docs.docker.com/compose/compose-file/). With the compose
-file a complete XOS solution based on Docker containers can be instantiated
-using a single command. To start the instance you can use the command:
-
+Then XOS can be brought up for CORD by running a few 'make' commands:
 ```
-$ docker-compose up -d
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make vtn
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make cord
 ```
 
-You should now be able to access the login page by visiting
-`http://localhost:8000` and log in using the default `padmin@vicci.org` account
-with password `letmein`.
-
-#### Configuring XOS for OpenStack
-
-If you have your own OpenStack cluster, and you would like to configure XOS to
-control it, copy the `admin-openrc.sh` credentials file for your cluster to
-this directory.  Make sure that OpenStack commands work from the local machine
-using the credentials, e.g., `source ./admin-openrc.sh; nova list`.  Then run:
-
-```
-$ make
-```
-
-XOS will be launched (the Makefile will run the `docker-compose up -d` command
-for you) and configured with the nodes and images available in your
-OpenStack cloud.  You can then log in to XOS as described above and start creating
-slices and instances.
+After the first 'make' command above, you will be able to login to XOS at
+*http://xos/* using username/password `padmin@vicci.org/letmein`.
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
new file mode 100644
index 0000000..d9fda9b
--- /dev/null
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -0,0 +1,175 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vsg_tenant:
+              node: service_vsg
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 207.141.192.128/27
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vbng_tenant:
+              node: service_vbng
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+          wan_container_gateway_ip: 207.141.192.158
+          wan_container_gateway_mac: a4:23:05:34:56:78
+          wan_container_netbits: 27
+      artifacts:
+          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    mysite:
+      type: tosca.nodes.Site
+
+    # Networks required by the CORD setup
+    mysite_vsg-access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - vsg_service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 111
+        requirements:
+            - provider_service:
+                node: service_volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/cord-pod/cord.yaml b/xos/configurations/cord-pod/cord.yaml
deleted file mode 100644
index c2d2fc8..0000000
--- a/xos/configurations/cord-pod/cord.yaml
+++ /dev/null
@@ -1,288 +0,0 @@
-tosca_definitions_version: tosca_simple_yaml_1_0
-
-description: Setup CORD-related services -- vOLT, vCPE, vBNG.
-
-imports:
-   - custom_types/xos.yaml
-
-topology_template:
-  node_templates:
-    # CORD Services
-    service_volt:
-      type: tosca.nodes.Service
-      requirements:
-          - vsg_tenant:
-              node: service_vsg
-              relationship: tosca.relationships.TenantOfService
-          - lan_network:
-              node: lan_network
-              relationship: tosca.relationships.UsesNetwork
-          - wan_network:
-              node: wan_network
-              relationship: tosca.relationships.UsesNetwork
-      properties:
-          view_url: /admin/cord/voltservice/$id$/
-          kind: vOLT
-
-    public_addresses:
-      type: tosca.nodes.AddressPool
-      properties:
-          addresses: 10.123.0.0/24 10.124.0.0/24
-
-    service_vsg:
-      type: tosca.nodes.VSGService
-      requirements:
-          - vbng_tenant:
-              node: service_vbng
-              relationship: tosca.relationships.TenantOfService
-      properties:
-          view_url: /admin/cord/vsgservice/$id$/
-          backend_network_label: hpc_client
-          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
-          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
-      artifacts:
-          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
-
-    service_vbng:
-      type: tosca.nodes.VBNGService
-      properties:
-          view_url: /admin/cord/vbngservice/$id$/
-# if unspecified, vbng observer will look for an ONOSApp Tenant and
-# generate a URL from its IP address
-#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
-
-    service_ONOS_vBNG:
-      type: tosca.nodes.ONOSService
-      requirements:
-      properties:
-          kind: onos
-          view_url: /admin/onos/onosservice/$id$/
-          no_container: true
-          rest_hostname: onos-cord
-
-#
-# To actually bring up the vBNG app
-# - Set up the dataplane using the ansible script
-# - Log into the vBNG ONOS and run 'devices' to get switch dpID
-# - Change the dpID values in vBNG ONOS app in XOS GUI
-# - (Synchronizer should copy the files to ONOS container immediately)
-# - Log into service_ONOS_vBNG VM and restart ONOS Docker container
-#   (Should roll this step into a Synchronizer)
-#f
-    vBNG_ONOS_app:
-      type: tosca.nodes.ONOSvBNGApp
-      requirements:
-          - onos_tenant:
-              node: service_ONOS_vBNG
-              relationship: tosca.relationships.TenantOfService
-          - vbng_service:
-              node: service_vbng
-              relationship: tosca.relationships.UsedByService
-      properties:
-          dependencies: org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd
-          config_network-cfg.json: >
-            {
-              "ports" : {
-                "of:0000000000000001/1" : {
-                  "interfaces" : [
-                    {
-                      "ips"  : [ "10.0.1.253/24" ],
-                      "mac"  : "00:00:00:00:00:99"
-                    }
-                  ]
-                },
-                "of:0000000000000001/2" : {
-                  "interfaces" : [
-                    {
-                      "ips"  : [ "10.254.0.2/24" ],
-                      "mac"  : "00:00:00:00:00:98"
-                    }
-                  ]
-                }
-              }
-            }
-          config_virtualbng.json: { get_artifact: [ SELF, virtualbng_json, LOCAL_FILE] }
-      artifacts:
-          virtualbng_json: /root/setup/virtualbng.json
-
-    service_ONOS_vOLT:
-      type: tosca.nodes.ONOSService
-      requirements:
-      properties:
-          kind: onos
-          view_url: /admin/onos/onosservice/$id$/
-          no_container: true
-          rest_hostname: onos-cord
-          rest_onos/v1/network/configuration/: >
-            {
-              "devices" : {
-                "of:0000000000000001" : {
-                  "accessDevice" : {
-                    "uplink" : "2",
-                    "vlan"   : "222",
-                    "defaultVlan" : "1"
-                  },
-                  "basic" : {
-                    "driver" : "pmc-olt"
-                  }
-                }
-              }
-            }
-
-
-    vOLT_ONOS_app:
-      type: tosca.nodes.ONOSvOLTApp
-      requirements:
-          - onos_tenant:
-              node: service_ONOS_vOLT
-              relationship: tosca.relationships.TenantOfService
-          - volt_service:
-              node: service_volt
-              relationship: tosca.relationships.UsedByService
-      properties:
-          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
-          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
-          component_config: >
-             {
-                "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
-                   "rabbit.user": "<rabbit_user>",
-                   "rabbit.password": "<rabbit_password>",
-                   "rabbit.host": "<rabbit_host>",
-                   "publish.kafka": "false",
-                   "publish.rabbit": "true",
-                   "volt.events.rabbit.topic": "notifications.info",
-                   "volt.events.rabbit.exchange": "voltlistener",
-                   "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
-                   "publish.volt.events": "true"
-                }
-             }
-#          config_network-cfg.json: >
-#            {
-#              "devices" : {
-#                "of:0000000000000001" : {
-#                  "accessDevice" : {
-#                    "uplink" : "2",
-#                    "vlan"   : "222",
-#                    "defaultVlan" : "1"
-#                  },
-#                  "basic" : {
-#                    "driver" : "default"
-#                  }
-#                }
-#              }
-#            }
-
-    # Network templates
-    Private:
-      type: tosca.nodes.NetworkTemplate
-
-    mysite:
-      type: tosca.nodes.Site
-
-    # CORD Slices
-    mysite_vsg:
-      description: vSG Controller Slice
-      type: tosca.nodes.Slice
-      requirements:
-          - vsg_service:
-              node: service_vsg
-              relationship: tosca.relationships.MemberOfService
-          - site:
-              node: mysite
-              relationship: tosca.relationships.MemberOfSite
-          - vsg_docker_image:
-              node: docker-vsg
-              relationship: tosca.relationships.UsesImage
-#      properties:
-#          default_isolation: container
-
-    # docker image for vSG containers
-    docker-vsg:
-      # TODO: need to attach this to mydeployment
-      type: tosca.nodes.Image
-      properties:
-        kind: container
-        container_format: na
-        disk_format: na
-        path: andybavier/docker-vcpe
-        tag: develop
-
-    # Let's add a user who can be administrator of the household
-    johndoe@myhouse.com:
-      type: tosca.nodes.User
-      properties:
-          password: letmein
-          firstname: john
-          lastname: doe
-      requirements:
-          - site:
-              node: mysite
-              relationship: tosca.relationships.MemberOfSite
-
-    # A subscriber
-    My House:
-       type: tosca.nodes.CORDSubscriber
-       properties:
-           service_specific_id: 123
-           firewall_enable: false
-           cdn_enable: false
-           url_filter_enable: false
-           url_filter_level: R
-       requirements:
-          - house_admin:
-              node: johndoe@myhouse.com
-              relationship: tosca.relationships.AdminPrivilege
-
-    Mom's PC:
-       type: tosca.nodes.CORDUser
-       properties:
-           mac: 01:02:03:04:05:06
-           level: PG_13
-       requirements:
-           - household:
-               node: My House
-               relationship: tosca.relationships.SubscriberDevice
-
-    Dad's PC:
-       type: tosca.nodes.CORDUser
-       properties:
-           mac: 90:E2:BA:82:F9:75
-           level: PG_13
-       requirements:
-           - household:
-               node: My House
-               relationship: tosca.relationships.SubscriberDevice
-
-    Jack's Laptop:
-       type: tosca.nodes.CORDUser
-       properties:
-           mac: 68:5B:35:9D:91:D5
-           level: PG_13
-       requirements:
-           - household:
-               node: My House
-               relationship: tosca.relationships.SubscriberDevice
-
-    Jill's Laptop:
-       type: tosca.nodes.CORDUser
-       properties:
-           mac: 34:36:3B:C9:B6:A6
-           level: PG_13
-       requirements:
-           - household:
-               node: My House
-               relationship: tosca.relationships.SubscriberDevice
-
-    My Volt:
-        type: tosca.nodes.VOLTTenant
-        properties:
-            service_specific_id: 123
-            s_tag: 222
-            c_tag: 432
-        requirements:
-            - provider_service:
-                node: service_volt
-                relationship: tosca.relationships.MemberOfService
-            - subscriber:
-                node: My House
-                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/cord-pod/docker-compose.yml b/xos/configurations/cord-pod/docker-compose.yml
index 6ea8c13..6f442af 100644
--- a/xos/configurations/cord-pod/docker-compose.yml
+++ b/xos/configurations/cord-pod/docker-compose.yml
@@ -13,9 +13,10 @@
         - xos_db
     volumes:
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-	- ../cord//xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - ../cord//xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
         - .:/root/setup:ro
         - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+        - ./images:/opt/xos/images:ro
 
 xos_synchronizer_onos:
     image: xosproject/xos-synchronizer-openstack
@@ -29,17 +30,28 @@
         - .:/root/setup:ro
         - ./id_rsa:/opt/xos/synchronizers/onos/onos_key:ro  # private key
 
-#xos_synchronizer_vcpe:
-#    image: xosproject/xos-synchronizer-openstack
-#    command: bash -c "sleep 120; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /root/setup/files/vcpe_synchronizer_config"
-#    labels:
-#        org.xosproject.kind: synchronizer
-#        org.xosproject.target: vcpe
-#    links:
-#        - xos_db
-#    volumes:
-#        - .:/root/setup:ro
-#        - ./id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro  # private key
+xos_synchronizer_vcpe:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vcpe/; chmod 0600 /opt/xos/synchronizers/vcpe/node_key; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /root/setup/files/vcpe_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vcpe
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+        - ./id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro  # private key
+
+xos_synchronizer_vtn:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vtn/vtn-synchronizer.py -C /opt/xos/synchronizers/vtn/vtn_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vtn
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
 
 #xos_synchronizer_vbng:
 #    image: xosproject/xos-synchronizer-openstack
@@ -74,3 +86,4 @@
         - ../cord/xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
         - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
         - ./id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
+        - ./id_rsa.pub:/opt/xos/synchronizers/vcpe/vcpe_public_key:ro
diff --git a/xos/configurations/cord-pod/files/vcpe_synchronizer_config b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
index 6ace486..46ee0c3 100644
--- a/xos/configurations/cord-pod/files/vcpe_synchronizer_config
+++ b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
@@ -34,10 +34,13 @@
 backoff_disabled=True
 save_ansible_output=True
 # set proxy_ssh to false on cloudlab
+full_setup=True
 proxy_ssh=True
 proxy_ssh_key=/root/setup/node_key
 proxy_ssh_user=root
-full_setup=True
+
+[networking]
+use_vtn=True
 
 [feefie]
 client_id='vicci_dev_central'
diff --git a/xos/configurations/cord-pod/images/README.md b/xos/configurations/cord-pod/images/README.md
new file mode 100644
index 0000000..aca55a9
--- /dev/null
+++ b/xos/configurations/cord-pod/images/README.md
@@ -0,0 +1,5 @@
+# VM images for XOS
+
+Any Cloud image files placed in this directory (with suffix .img) will be automatically
+imported by XOS and added to Glance (OpenStack's image repository).  For instance, the image
+`trusty-server-multi-nic.img` will be imported with name `trusty-server-multi-nic`.
diff --git a/xos/configurations/cord-pod/make-virtualbng-json.sh b/xos/configurations/cord-pod/make-virtualbng-json.sh
new file mode 100644
index 0000000..993643c
--- /dev/null
+++ b/xos/configurations/cord-pod/make-virtualbng-json.sh
@@ -0,0 +1,38 @@
+FN=$SETUPDIR/virtualbng.json
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "localPublicIpPrefixes" : [
+        "10.254.0.128/25"
+    ],
+    "nextHopIpAddress" : "10.254.0.1",
+    "publicFacingMac" : "00:00:00:00:00:66",
+    "xosIpAddress" : "10.11.10.1",
+    "xosRestPort" : "9999",
+    "hosts" : {
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    ((I++))
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"," >> $FN
+    else
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"" >> $FN
+    fi
+done
+
+cat >> $FN <<EOF
+    }
+}
+EOF
diff --git a/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh b/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
index 309df5e..5239267 100755
--- a/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
+++ b/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
@@ -9,12 +9,18 @@
     "apps" : {
         "org.onosproject.cordvtn" : {
             "cordvtn" : {
-                "gatewayMac" : "00:00:00:00:00:01",
-                "localManagementIp": "10.90.0.147/24",
+                "privateGatewayMac" : "00:00:00:00:00:01",
+                "localManagementIp": "172.27.0.1/24",
                 "ovsdbPort": "6641",
                 "sshPort": "22",
                 "sshUser": "root",
                 "sshKeyFile": "/root/node_key",
+                "publicGateways": [
+                    {
+                        "gatewayIp": "207.141.192.158",
+                        "gatewayMac": "a4:23:05:34:56:78"
+                    }
+                ],
                 "nodes" : [
 EOF
 
@@ -37,7 +43,7 @@
 
     PHYPORT=mlx0
     # How to set LOCALIP?
-    LOCALIP=10.0.2.1
+    LOCALIPNET="192.168.199"
 
     ((I++))
     cat >> $FN <<EOF
@@ -46,7 +52,7 @@
                       "hostManagementIp": "$NODEIP/24",
                       "bridgeId": "of:000000000000000$I",
                       "dataPlaneIntf": "$PHYPORT",
-                      "dataPlaneIp": "$LOCALIP/24"
+                      "dataPlaneIp": "$LOCALIPNET.$I/24"
 EOF
     if [[ "$I" -lt "$NODECOUNT" ]]; then
         echo "                    }," >> $FN
diff --git a/xos/configurations/cord-pod/mgmt-net.yaml b/xos/configurations/cord-pod/mgmt-net.yaml
new file mode 100644
index 0000000..2bd0173
--- /dev/null
+++ b/xos/configurations/cord-pod/mgmt-net.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Set up management network for CORD POD
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    management_template:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    management:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 172.27.0.0/24
+      requirements:
+          - network_template:
+              node: management_template
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_management
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_management:
+      description: This slice exists solely to own the management network
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
diff --git a/xos/configurations/cord-pod/vtn-external.yaml b/xos/configurations/cord-pod/vtn-external.yaml
index eed1d1c..0aaee67 100644
--- a/xos/configurations/cord-pod/vtn-external.yaml
+++ b/xos/configurations/cord-pod/vtn-external.yaml
@@ -1,12 +1,13 @@
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+description: Set up ONOS VTN app
 
 imports:
    - custom_types/xos.yaml
 
 topology_template:
   node_templates:
+
     service_ONOS_VTN:
       type: tosca.nodes.ONOSService
       requirements:
@@ -23,7 +24,7 @@
               node: service_ONOS_VTN
               relationship: tosca.relationships.TenantOfService
       properties:
-          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.openstackswitching, org.onosproject.cordvtn
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn, org.onosproject.olt, org.onosproject.igmp, org.onosproject.cordmcast
           rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
       artifacts:
           vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
diff --git a/xos/configurations/cord/README-VTN.md b/xos/configurations/cord/README-VTN.md
index 2d9b7aa..b3c0c61 100644
--- a/xos/configurations/cord/README-VTN.md
+++ b/xos/configurations/cord/README-VTN.md
@@ -1,4 +1,4 @@
-vtn notes:
+# vtn notes:
 
 see also: https://github.com/hyunsun/documentations/wiki/Neutron-ONOS-Integration-for-CORD-VTN#onos-setup
 
@@ -15,7 +15,7 @@
         use_vtn=True
     supervisorctl restart observer
 
-ctl node:
+### ctl node:
 
     # set ONOS_VTN_HOSTNAME to the host where the VTN container was installed
     ONOS_VTN_HOSTNAME="cp-2.smbaker-xos5.xos-pg0.clemson.cloudlab.us"
@@ -30,7 +30,7 @@
     # not still an issue lurking...
     cat > /usr/local/etc/neutron/plugins/ml2/conf_onos.ini <<EOF
     [onos]
-    url_path = http://$ONOS_VTN_HOSTNAME:8181/onos/openstackswitching
+    url_path = http://$ONOS_VTN_HOSTNAME:8181/onos/cordvtn
     username = karaf
     password = karaf
     EOF
@@ -41,7 +41,7 @@
     # files. Maybe it can be restarted using systemctl instead...
     /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /usr/local/etc/neutron/plugins/ml2/conf_onos.ini
 
-Compute nodes and nm nodes:
+### Compute nodes and nm nodes:
 
     cd xos/configurations/cord/dataplane
     ./generate-bm.sh > hosts-bm
@@ -55,22 +55,14 @@
 
 Additional compute node stuff:
 
-Br-flat-lan-1 needs to be deleted, since VTN will be attaching br-int directly to the eth device that br-flat-lan-1 was using. Additionally, we need to assign an IP address to br-int (sounds like Hyunsun is working on having VTN do that for us). Adding the route was not in Hyunsun's instructions, but I found I had to do it in order to get the compute nodes to talk to one another.
+I've been deleting any existing unused bridges. Not sure if it's necesary.
 
     ovs-vsctl del-br br-tun
     ovs-vsctl del-br br-flat-lan-1
-    ip addr add <addr-that-was-assinged-to-flat-lan-1> dev br-int
-    ip link set br-int up
-    ip route add <network-that-was-assigned-to-flat-lan-1>/24 dev br-int
-    
-To get the management network working, we need to create management network template, slice, and network. configurations/cord/vtn.yaml will do this for you. Then add a connection to the management network for any slice that needs management connectivity. Note the subnet that gets assigned to the management network. Management-gateway-ip is the .1 address on the subnet. On the compute node:
 
-    ip addr add <management-gateway-ip>/24 dev br-int
+To get the management network working, we need to create management network template, slice, and network. configurations/cord/vtn.yaml will do this for you. Then add a connection to the management network for any slice that needs management connectivity.
     
-For development, I suggest using the bash configuration (remember to start the ONOS observer manually) so that 
-there aren't a bunch of preexisting Neutron networks and nova instances to get in the way. 
-
-Notes:
+### Notes:
 * I've configured the OpenvSwitch switches to use port 6641 instead of port 6640. This is because the VTN app listens on 6640
 itself, and since we're running it in docker 'host' networking mode now, it would conflict with an Openvswitch that was
 also listening on 6640.
@@ -79,7 +71,7 @@
 * Note that the VTN Synchronizer isn't started automatically. It's only use for inter-Service connectivity, so no need to mess with it until intra-Slice connectivity is working first. 
 * Note that the VTN Synchronizer won't connect non-access networks. Any network templates you want VTN to connect must have Access set to "Direct" or "Indirect". 
 
-There is no management network yet, so no way to SSH into the slices. I've been setting up a VNC tunnel, like this:
+In case management network isn't working, you can use a VNC tunnel, like this:
 
     # on compute node, run the following and note the IP address and port number
     virsh vncdisplay <instance-id>
@@ -92,13 +84,13 @@
 
 Then open a VNC session to the local port on your local machine. You'll have a console on the Instance. The username is "Ubuntu" and the password can be obtained from your cloudlab experiment description
 
-Things that can be tested:
+### Things that can be tested:
 
 * Create an Instance, it should have a Private network, and there should be a tap attached from the instance to br-int
 * Two Instances in the same Slice can talk to one another. They can be on the same machine or different machines.
 * Two Slices can talk to one another if the slices are associated with Services and those Services have a Tenancy relationship between them. Note that 1) The VTN Synchronizer must be running, 2) There must be a Private network with Access=[Direct|Indirect], and 3) The connectivity is unidirectional, from subscriber service to provider service.
 
-Testing service composition
+### Testing service composition
 
 1. Change the private network template's 'Access' field from None to Direct
 2. Create a Service, Service-A
@@ -113,3 +105,47 @@
 11. You should see the pings arrive and responses sent out. Note that the ping responses will not reach Slice-1, since VTN traffic is unidirectional.
 12. Delete the Tenancy relation you created in Step #7. The ping traffic should no longer appear in the tcpdump.
 
+### Getting external connectivity working on cloudlab
+
+On head node:
+
+    ovs-vsctl del-br br-flat-lan-1
+    ifconfig eth2 10.123.0.1
+    iptables --table nat --append POSTROUTING --out-interface br-ex -j MASQUERADE
+    arp -s 10.123.0.3 fa:16:3e:ea:11:0a
+    
+Substitute for your installation:
+
+    10.123.0.3 = wan_ip of vSG
+    10.123.0.1 = wan gateway
+    fa:16:3e:ea:11:0a = wan_mac of vSG
+    00:8c:fa:5b:09:d8 = wan_mac of gateway
+    
+### Setting up a test-client
+
+Before setting up VTN, create a bridge and attach it to the dataplane device on each compute node:
+
+    brctl addbr br-inject
+    brctl addif br-inject eth3   # substitute dataplane eth device here, may be different on each compute node
+    ip link set br-inject up
+    ip link set dev br-inject promisc on
+    
+Then update the network-config attribute of the VTN ONOS App in XOS to use a dataplaneIntf of br-inject instead of the eth device. Bring up VTN and a VSG. WAN connectivity and everything else should be working fine. 
+
+Add a new slice, mysite_client, and make sure to give it both a private and a management network. Bring up an instance on the same node as the vSG you want to test. On the compute node, run the following:
+
+    $MAC=<make-up-some-mac>
+    $INSTANCE=<instance-id>
+    virsh attach-interface --domain $INSTANCE --type bridge --source br-inject --model virtio --mac $MAC --config --live
+    
+Log into the vSG via the management interface. Inside of the vSG run the following:
+
+    STAG=<your s-tag here>
+    CTAG=<your c-tag here>
+    ip link add link eth2 eth2.$STAG type vlan id $STAG
+    ip link add link eth2.$STAG eth2.$STAG.$CTAG type vlan id $CTAG
+    ip link set eth2.$STAG up
+    ip link set eth2.$STAG.$CTAG up
+    ip addr add 192.168.0.2/24 dev eth2.$STAG.$CTAG
+    ip route del default
+    ip route add default via 192.168.0.1
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/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index ec2cd6f..07d4b68 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -24,6 +24,7 @@
           view_url: /admin/cord/voltservice/$id$/
           kind: vOLT
 
+    # set a pool of addresses that we can hand out for the VSG Wan.
     public_addresses:
       type: tosca.nodes.AddressPool
       properties:
diff --git a/xos/configurations/cord/dataplane/cleanup.sh b/xos/configurations/cord/dataplane/cleanup.sh
index 9860de7..120454d 100755
--- a/xos/configurations/cord/dataplane/cleanup.sh
+++ b/xos/configurations/cord/dataplane/cleanup.sh
@@ -26,8 +26,11 @@
 echo "Waiting 5 seconds..."
 sleep 5
 
+cleanup_network lan_network
 cleanup_network wan_network
 cleanup_network mysite_vcpe-private
+cleanup_network mysite_vsg-access
+cleanup_network management
 
 echo "Deleting networks"
 # Delete all networks beginning with mysite_
@@ -42,3 +45,5 @@
 neutron net-delete public_network || true
 neutron net-delete hpc_client_network || true
 neutron net-delete ceilometer_network || true
+neutron net-delete management || true
+neutron net-delete mysite_vsg-access || true
diff --git a/xos/configurations/cord/make-vtn-networkconfig-json.sh b/xos/configurations/cord/make-vtn-networkconfig-json.sh
index 8a8b233..2cccd65 100644
--- a/xos/configurations/cord/make-vtn-networkconfig-json.sh
+++ b/xos/configurations/cord/make-vtn-networkconfig-json.sh
@@ -9,12 +9,18 @@
     "apps" : {
         "org.onosproject.cordvtn" : {
             "cordvtn" : {
-                "gatewayMac" : "00:00:00:00:00:01",
+                "privateGatewayMac" : "00:00:00:00:00:01",
                 "localManagementIp": "172.27.0.1/24",
                 "ovsdbPort": "6641",
                 "sshPort": "22",
                 "sshUser": "root",
                 "sshKeyFile": "/root/node_key",
+                "publicGateways": [
+                    {
+                        "gatewayIp": "10.123.0.1",
+                        "gatewayMac": "00:8c:fa:5b:09:d8"
+                    }
+                ],
                 "nodes" : [
 EOF
 
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index aad475d..20f997a 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -25,6 +25,13 @@
 	sudo docker exec -ti frontend_xos_1 bash
 
 mock-cord:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/cord.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord/xos_cord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+mock-mcord:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/mcord.yaml
+	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/frontend/mocks/xos_mcord_config /opt/xos/xos_configuration/
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
diff --git a/xos/configurations/frontend/README.md b/xos/configurations/frontend/README.md
index c8f4097..b1a689c 100644
--- a/xos/configurations/frontend/README.md
+++ b/xos/configurations/frontend/README.md
@@ -42,6 +42,7 @@
 Sometimes while developing the GUI is usefull to have control over the DataModel. Sample `tosca` recipes for different configuration are defined in the `mocks` folder, and corresponding `make` commands are provided.
 
 - Bring up the **CORD** data model: `make mock-cord`
+- - Bring up the **M-CORD** data model: `make mock-mcord`
 
 ## JS Styleguide
 
diff --git a/xos/configurations/frontend/docker-compose.yml b/xos/configurations/frontend/docker-compose.yml
index c7c9c19..2ad8f7a 100644
--- a/xos/configurations/frontend/docker-compose.yml
+++ b/xos/configurations/frontend/docker-compose.yml
@@ -24,3 +24,6 @@
       - ../../core/static:/opt/xos/core/static
       - ../../templates/admin:/opt/xos/templates/admin
       - ../../configurations:/opt/xos/configurations
+      - ../../xos:/opt/xos/xos
+      - ../../core/views:/opt/xos/core/views
+      - ../../services:/opt/xos/services
diff --git a/xos/configurations/frontend/mocks/MCORDServiceN.yaml b/xos/configurations/frontend/mocks/MCORDServiceN.yaml
new file mode 100644
index 0000000..bef7bb3
--- /dev/null
+++ b/xos/configurations/frontend/mocks/MCORDServiceN.yaml
@@ -0,0 +1,89 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+    tosca.nodes.MCORDComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: A Service Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: generic

+                description: Kind of component

+

+topology_template:

+  node_templates:

+    service_mcord:

+      type: tosca.nodes.Service

+      requirements:

+      properties:

+          kind: mcordservice

+

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    mcord_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: mcord_service_internal_net

+          cidr: 172.16.16.0/24

+          start_ip: 172.16.16.1

+          end_ip: 172.16.16.5

+          gateway_ip: 172.16.16.1

+

+      requirements:

+          - network_template:

+              node: Private

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+

+    ubuntu-14.04-server-cloudimg-amd64-disk1:

+      type: tosca.nodes.Image

+

+    trusty-server-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_mcord_slice1:

+      description: MCORD Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - mcord_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: ubuntu-14.04-server-cloudimg-amd64-disk1 

+#                node: mcord-server-image-s1

+                relationship: tosca.relationships.DefaultImage

+      properties:

+          default_flavor: m1.medium

+          default_node: compute9 

+

+    my_service_mcord_component1:

+      description: MCORD Service default Component

+      type: tosca.nodes.MCORDComponent

+      requirements:

+          - provider_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - mcord_slice:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

diff --git a/xos/configurations/frontend/mocks/mcord.yaml b/xos/configurations/frontend/mocks/mcord.yaml
new file mode 100644
index 0000000..6c10ad3
--- /dev/null
+++ b/xos/configurations/frontend/mocks/mcord.yaml
@@ -0,0 +1,319 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # M-CORD Services
+    
+    # RAN
+    vBBU:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vBBU
+          kind: RAN
+
+    eSON:
+      type: tosca.nodes.Service
+      properties:
+          view_url: http://www.google.com
+          kind: RAN
+
+    # EPC
+    vMME:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vMME
+          kind: EPC
+
+    vSGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vSGW
+          kind: EPC
+
+    vPGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vPGW
+          kind: EPC
+
+    # EDGE
+    Cache:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Cache
+          icon_url: /static/mCordServices/service_cache.png
+          kind: EDGE
+
+    Firewall:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Firewall
+          icon_url: /static/mCordServices/service_firewall.png
+          kind: EDGE
+
+    Video Optimization:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Video%20Optimization
+          icon_url: /static/mCordServices/service_video.png
+          kind: EDGE
+          
+    # Images
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+    # Deployments
+    StanfordDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    # Site
+    stanford:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Stanford University
+          site_url: https://www.stanford.edu/
+      requirements:
+          - deployment:
+               node: StanfordDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: CloudLab
+                       relationship: tosca.relationships.UsesController
+
+
+    # Nodes
+    node1.stanford.edu:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: StanfordDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    # Slices
+    stanford_slice:
+      description: Slice that contains sample instances
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: stanford
+              relationship: tosca.relationships.MemberOfSite
+
+    # Instances
+    BBU_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    BBU_service_instance2:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    MME_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    SGW_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    PGW_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    # Let's add a user who can be administrator of the household
+    johndoe@stanford.us:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: stanford
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    Stanford:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@stanford.us
+              relationship: tosca.relationships.AdminPrivilege
+
+    Barbera Lapinski:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Norbert Shumway:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Fay Muldoon:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Janene Earnest:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+
+    Topology:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosMcordTopology
+
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosCeilometerDashboard
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - mcord_dashboard:
+              node: Topology
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/configurations/frontend/mocks/xos_mcord_config b/xos/configurations/frontend/mocks/xos_mcord_config
new file mode 100644
index 0000000..7730f3b
--- /dev/null
+++ b/xos/configurations/frontend/mocks/xos_mcord_config
@@ -0,0 +1,6 @@
+[gui]
+branding_name=M-CORD
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/mcord-bg2.jpg
+service_view_class=core.views.mCordServiceGrid.ServiceGridView
diff --git a/xos/configurations/frontend/service_chain.yaml b/xos/configurations/frontend/service_chain.yaml
new file mode 100644
index 0000000..557f98e
--- /dev/null
+++ b/xos/configurations/frontend/service_chain.yaml
@@ -0,0 +1,204 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup two subscriber with related service chain, use for development of serviceTopology view.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Subscribers
+    Night's Watch:
+      type: tosca.nodes.CORDSubscriber
+      properties:
+        service_specific_id: 123
+        firewall_enable: false
+        cdn_enable: false
+        url_filter_enable: false
+        url_filter_level: R
+
+    # CORD Users for Night's Watch
+    Jhon Snow:
+      type: tosca.nodes.CORDUser
+      properties:
+        mac: 01:02:03:04:05:06
+        level: PG_13
+      requirements:
+        - household:
+            node: Night's Watch
+            relationship: tosca.relationships.SubscriberDevice
+
+    House Targaryen:
+      type: tosca.nodes.CORDSubscriber
+      properties:
+        service_specific_id: 321
+        firewall_enable: false
+        cdn_enable: false
+        url_filter_enable: false
+        url_filter_level: R
+
+    # CORD Users for House Targaryen
+    Daenerys:
+      type: tosca.nodes.CORDUser
+      properties:
+        mac: 06:05:04:03:02:01
+        level: PG_13
+      requirements:
+        - household:
+            node: House Targaryen
+            relationship: tosca.relationships.SubscriberDevice
+
+    # vOLT Tenants
+    Night's Watch vOLT:
+      type: tosca.nodes.VOLTTenant
+      properties:
+        service_specific_id: 123
+        s_tag: 123
+        c_tag: 456
+      requirements:
+        - provider_service:
+            node: service_volt
+            relationship: tosca.relationships.MemberOfService
+        - subscriber:
+            node: Night's Watch
+            relationship: tosca.relationships.BelongsToSubscriber
+
+    Targaryen vOLT:
+      type: tosca.nodes.VOLTTenant
+      properties:
+        service_specific_id: 321
+        s_tag: 321
+        c_tag: 654
+      requirements:
+        - provider_service:
+            node: service_volt
+            relationship: tosca.relationships.MemberOfService
+        - subscriber:
+            node: House Targaryen
+            relationship: tosca.relationships.BelongsToSubscriber
+
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+        - vcpe_tenant:
+            node: service_vcpe
+            relationship: tosca.relationships.TenantOfService
+        - lan_network:
+            node: lan_network
+            relationship: tosca.relationships.UsesNetwork
+        - wan_network:
+            node: wan_network
+            relationship: tosca.relationships.UsesNetwork
+      properties:
+        view_url: /admin/cord/voltservice/$id$/
+        kind: vOLT
+
+    service_vcpe:
+      type: tosca.nodes.VCPEService
+      requirements:
+        - vbng_tenant:
+            node: service_vbng
+            relationship: tosca.relationships.TenantOfService
+      properties:
+        view_url: /admin/cord/vcpeservice/$id$/
+        backend_network_label: hpc_client
+        public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+        private_key_fn: /opt/xos/observers/vcpe/vcpe_private_key
+      artifacts:
+        pubkey: /root/.ssh/id_rsa.pub #is this right?
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+        view_url: /admin/cord/vbngservice/$id$/
+
+    # Networks required
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+        ip_version: 4
+      requirements:
+        - network_template:
+            node: Private
+            relationship: tosca.relationships.UsesNetworkTemplate
+        - owner:
+            node: mysite_vcpe
+            relationship: tosca.relationships.MemberOfSlice
+        - connection:
+            node: mysite_vcpe
+            relationship: tosca.relationships.ConnectsToSlice
+        - connection:
+            node: mysite_volt
+            relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+        ip_version: 4
+      requirements:
+        - network_template:
+            node: Private
+            relationship: tosca.relationships.UsesNetworkTemplate
+        - owner:
+            node: mysite_vcpe
+            relationship: tosca.relationships.MemberOfSlice
+        - connection:
+            node: mysite_vcpe
+            relationship: tosca.relationships.ConnectsToSlice
+        - connection:
+            node: mysite_vbng
+            relationship: tosca.relationships.ConnectsToSlice
+
+    # Network templates
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    # Sites
+    mysite:
+      type: tosca.nodes.Site
+
+    # Slices
+    mysite_vcpe:
+      description: vCPE Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+        - vcpe_service:
+            node: service_vcpe
+            relationship: tosca.relationships.MemberOfService
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - vcpe_docker_image:
+            node: docker-vcpe
+            relationship: tosca.relationships.UsesImage
+      properties:
+          default_isolation: container
+
+    mysite_vbng:
+      description: slice running OVS controlled by vBNG
+      type: tosca.nodes.Slice
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+
+    mysite_volt:
+      description: OVS controlled by vOLT
+      type: tosca.nodes.Slice
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+
+    # docker image for vcpe containers
+    docker-vcpe:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: andybavier/docker-vcpe
+        tag: develop
+
diff --git a/xos/configurations/opencloud/docker-compose.yml b/xos/configurations/opencloud/docker-compose.yml
index 3813dee..b44c828 100644
--- a/xos/configurations/opencloud/docker-compose.yml
+++ b/xos/configurations/opencloud/docker-compose.yml
@@ -16,6 +16,7 @@
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
         - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
         - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+        - ./images:/opt/xos/images:ro
 
 xos_synchronizer_hpc:
     image: xosproject/xos-synchronizer-openstack
diff --git a/xos/configurations/test/README b/xos/configurations/test/README.md
similarity index 86%
rename from xos/configurations/test/README
rename to xos/configurations/test/README.md
index 31f7786..37af594 100644
--- a/xos/configurations/test/README
+++ b/xos/configurations/test/README.md
@@ -1,2 +1,4 @@
+#CORD Test Configuration
+
 This configuration launches the XOS container on cloudlab and runs a test suite. The test results will be printed to
 the console, and then the docker container will exit. 
diff --git a/xos/configurations/vtn/cord-vtn-vsg.yaml b/xos/configurations/vtn/cord-vtn-vsg.yaml
index bcb6847..1b26bba 100644
--- a/xos/configurations/vtn/cord-vtn-vsg.yaml
+++ b/xos/configurations/vtn/cord-vtn-vsg.yaml
@@ -34,6 +34,10 @@
           backend_network_label: hpc_client
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
           private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+          wan_container_gateway_ip: 10.123.0.1
+          wan_container_gateway_mac: 00:8c:fa:5b:09:d8
+          wan_container_netbits: 24
+          dns_servers: 8.8.8.8, 8.8.4.4
       artifacts:
           pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
 
diff --git a/xos/configurations/vtn/docker-compose.yml b/xos/configurations/vtn/docker-compose.yml
index 7fb68f1..0fa718b 100644
--- a/xos/configurations/vtn/docker-compose.yml
+++ b/xos/configurations/vtn/docker-compose.yml
@@ -42,7 +42,7 @@
 
 xos:
     image: xosproject/xos
-    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    command: bash -c "python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations"
     ports:
         - "9999:8000"
     links:
diff --git a/xos/configurations/vtn/vtn.yaml b/xos/configurations/vtn/vtn.yaml
index 9b36852..3928ba1 100644
--- a/xos/configurations/vtn/vtn.yaml
+++ b/xos/configurations/vtn/vtn.yaml
@@ -58,7 +58,7 @@
               node: service_ONOS_VTN
               relationship: tosca.relationships.TenantOfService
       properties:
-          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.openstackswitching, org.onosproject.cordvtn
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn
           rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
       artifacts:
           vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
diff --git a/xos/core/admin.py b/xos/core/admin.py
index c6e3e93..28d99fd 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1256,7 +1256,7 @@
                ]
     readonly_fields = ('backend_status_text', )
 
-    suit_form_tabs =(('general','Image Details'),('instances','Instances'),('imagedeployments','Deployments'), ('controllerimages', 'Controllers'))
+    suit_form_tabs =(('general','Image Details'),('instances','Instances'),('imagedeployments','Deployments'), ('admin-only', 'Admin-Only'))
 
     inlines = [InstanceInline, ControllerImagesInline]
 
@@ -1898,7 +1898,7 @@
     suit_form_tabs = (('general','Network Template Details'), ('netparams', 'Parameters') )
 
 class PortAdmin(XOSBaseAdmin):
-    list_display = ("backend_status_icon", "name", "id", "ip")
+    list_display = ("backend_status_icon", "id", "ip")
     list_display_links = ('backend_status_icon', 'id')
     readonly_fields = ("subnet", )
     inlines = [NetworkParameterInline]
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index 8924592..4f2c5dd 100644
--- a/xos/core/models/network.py
+++ b/xos/core/models/network.py
@@ -264,6 +264,7 @@
     ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
     port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron port id")
     mac = models.CharField(null=True, blank=True, max_length=256, help_text="MAC address associated with this port")
+    xos_created = models.BooleanField(default=False) # True if XOS created this port in Neutron, False if port created by Neutron and observed by XOS
 
     class Meta:
         unique_together = ('network', 'instance')
@@ -353,20 +354,32 @@
         with transaction.atomic():
             ap = AddressPool.objects.get(pk=self.pk)
             if ap.addresses:
-                addresses = ap.addresses or ""
-                parts = addresses.split()
-                addr = parts.pop(0)
-                ap.addresses = " ".join(parts)
-
-                inuse = ap.inuse or ""
-                parts = inuse.split()
-                if not (addr in parts):
-                    parts.insert(0,addr)
-                    ap.inuse = " ".join(parts)
-
-                ap.save()
+                avail_ips = ap.addresses.split()
             else:
-                addr = None
+                avail_ips = []
+
+            if ap.inuse:
+                inuse_ips = ap.inuse.split()
+            else:
+                inuse_ips = []
+
+            while avail_ips:
+                addr = avail_ips.pop(0)
+
+                if addr in inuse_ips:
+                    # This may have happened if someone re-ran the tosca
+                    # recipe and 'refilled' the AddressPool while some addresses
+                    # were still in use.
+                    continue
+
+                inuse_ips.insert(0,addr)
+
+                ap.inuse = " ".join(inuse_ips)
+                ap.addresses = " ".join(avail_ips)
+                ap.save()
+                return addr
+
+            addr = None
         return addr
 
     def put_address(self, addr):
diff --git a/xos/core/models/tag.py b/xos/core/models/tag.py
index d774800..76a4e2e 100644
--- a/xos/core/models/tag.py
+++ b/xos/core/models/tag.py
@@ -27,6 +27,10 @@
     def can_update(self, user):
         return user.can_update_root()
 
+    @classmethod
+    def select_by_content_object(cls, obj):
+        return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
+
     @staticmethod
     def select_by_user(user):
         return Tag.objects.all()
diff --git a/xos/core/static/mCordServices/service_cache.png b/xos/core/static/mCordServices/service_cache.png
new file mode 100644
index 0000000..91ad760
--- /dev/null
+++ b/xos/core/static/mCordServices/service_cache.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_common.png b/xos/core/static/mCordServices/service_common.png
new file mode 100644
index 0000000..9fda14e
--- /dev/null
+++ b/xos/core/static/mCordServices/service_common.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_firewall.png b/xos/core/static/mCordServices/service_firewall.png
new file mode 100644
index 0000000..a8b5480
--- /dev/null
+++ b/xos/core/static/mCordServices/service_firewall.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_video.png b/xos/core/static/mCordServices/service_video.png
new file mode 100644
index 0000000..17e87be
--- /dev/null
+++ b/xos/core/static/mCordServices/service_video.png
Binary files differ
diff --git a/xos/core/static/mcord-bg.jpg b/xos/core/static/mcord-bg.jpg
new file mode 100644
index 0000000..802d590
--- /dev/null
+++ b/xos/core/static/mcord-bg.jpg
Binary files differ
diff --git a/xos/core/static/mcord-bg2.jpg b/xos/core/static/mcord-bg2.jpg
new file mode 100644
index 0000000..1dde1b2
--- /dev/null
+++ b/xos/core/static/mcord-bg2.jpg
Binary files differ
diff --git a/xos/core/static/xos.css b/xos/core/static/xos.css
index 592bb7c..0ec638c 100644
--- a/xos/core/static/xos.css
+++ b/xos/core/static/xos.css
@@ -23,9 +23,9 @@
   overflow-x: hidden;
 }
 
-/*#wrap {
+#wrap {
   min-height: 100%;
-}*/
+}
 
 /* ************************* LOGIN PAGE ************************* */
 
@@ -44,6 +44,7 @@
     -moz-transition: all 0.5s ease;
     -o-transition: all 0.5s ease;
     transition: all 0.5s ease;
+    min-height: 900px;
 }
 
 #wrapper.toggled {
@@ -74,6 +75,11 @@
     width: 100%;
     position: absolute;
     padding: 15px;
+    min-height: 900px;
+}
+
+#page-content-wrapper .container-fluid {
+  min-height: 900px;
 }
 
 #wrapper.toggled #page-content-wrapper {
@@ -325,6 +331,11 @@
 border: 0px;
 }
 
+.ui-tabs-panel {
+  min-height: 700px;
+  position: relative;
+}
+
 .ui-tabs .ui-tabs-nav {
   padding: 0 !important;
 }
@@ -1374,12 +1385,28 @@
 button.ui-dialog-titlebar-close:after {
     content: "\e014";
 }
-/* VCPe ADMIN FIX */
-/*form#vcpeservice_form ul li {
-    display: inline-block;
-    background: red;
-    margin-top: 10px;
-    width: auto;
-    padding: 10px;
-    border-radius: 5px;
+/* M-CORD SERVICE GRID */
+.m-cord .kind-container h2{
+  background-color: #9c0001;
+  padding: 10px;
+  color: #fff;
+  border-radius: 4px;
+  cursor: pointer;
+  box-shadow: 1px 2px 2px black;
 }
+
+.m-cord .kind-container img.img-responsive {
+  display: inline-block;
+}
+
+.m-cord .kind-container .service-container{
+  height: 0px;
+  overflow: hidden;
+  opacity: 0;
+  transition: all .5s ease-in-out;
+}
+
+.m-cord .kind-container.active .service-container{
+  height: 162px;
+  opacity: 1;
+}
\ No newline at end of file
diff --git a/xos/core/views/mCordServiceGrid.py b/xos/core/views/mCordServiceGrid.py
new file mode 100644
index 0000000..56c820a
--- /dev/null
+++ b/xos/core/views/mCordServiceGrid.py
@@ -0,0 +1,72 @@
+from django.http import HttpResponse
+from django.views.generic import TemplateView, View
+from django import template
+from django.shortcuts import render
+from core.models import *
+import json
+import os
+import time
+import tempfile
+
+
+class ServiceGridView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    # I hate myself for doing this
+    script = """
+    <script type="text/javascript">
+        $(window).ready(function(){
+            $('.kind-container').on('click', function(){
+                $(this).toggleClass('active')
+            });
+        })
+    </script>
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        head_template = self.head_template
+        tail_template = self.tail_template
+        html = self.script
+        html = html + '<div class="col-xs-12 m-cord">'
+
+        # Select the unique kind of services
+        for kind in Service.objects.values('kind').distinct():
+
+            html = html + '<div class="kind-container row">'
+            html = html + '<div class="col-xs-12"><h2>%s</h2></div>' % (kind["kind"])
+
+            # for each kind select services
+            for service in Service.objects.filter(kind=kind["kind"]):
+                image_url = service.icon_url
+                if (not image_url):
+                    image_url = "/static/mCordServices/service_common.png"
+                #if service.view_url.startswith("http"):
+                #    target = 'target="_blank"'
+                #else:
+                #    target = ''
+                target = ''
+
+                html = html + '<div class="col-xs-4 text-center service-container">'
+                html = html + '<a href="%s" %s>' % (service.view_url, target)
+                html = html + '<img class="img-responsive" src="%s">' % (image_url)
+                html = html + "<h4>" + service.name + "</h4>"
+                html = html + '</a>'
+                html = html + "</div>"
+
+            html = html + "</div>"
+
+        html = html + "</div>"
+        t = template.Template(head_template + html + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs
+        )
diff --git a/xos/core/views/serviceGraph.py b/xos/core/views/serviceGraph.py
index 5ce0581..874d7a4 100644
--- a/xos/core/views/serviceGraph.py
+++ b/xos/core/views/serviceGraph.py
@@ -7,6 +7,7 @@
 import time
 import tempfile
 
+
 class ServiceGridView(TemplateView):
     head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
        {% load admin_static %}
@@ -21,7 +22,7 @@
 
         html = '<table class="service-grid"><tr>'
 
-        icons=[]
+        icons = []
         for service in Service.objects.all():
             view_url = service.view_url
             if (not view_url):
@@ -32,27 +33,27 @@
             if (not image_url):
                 image_url = "/static/primarycons_blue/gear_2.png"
 
-            icons.append( {"name": service.name, "view_url": view_url, "image_url": image_url} )
+            icons.append({"name": service.name, "view_url": view_url, "image_url": image_url})
 
-        icons.append( {"name": "Tenancy Graph", "view_url": "/serviceGraph.png", "image_url": "/static/primarycons_blue/service_graph.png", "horiz_rule": True} )
-        icons.append( {"name": "Add Service", "view_url": "/admin/core/service/add/", "image_url": "/static/primarycons_blue/plus.png"} )
+        icons.append({"name": "Tenancy Graph", "view_url": "/serviceGraph.png", "image_url": "/static/primarycons_blue/service_graph.png", "horiz_rule": True})
+        icons.append({"name": "Add Service", "view_url": "/admin/core/service/add/", "image_url": "/static/primarycons_blue/plus.png"})
 
-        i=0
+        i = 0
         for icon in icons:
             if icon.get("horiz_rule", False):
                 html = html + "</tr><tr><td colspan=4><hr></td></tr><tr>"
-                i=0
+                i = 0
 
             service_name = icon["name"]
             view_url = icon["view_url"]
             image_url = icon["image_url"]
 
-            if (i%4) == 0:
+            if (i % 4) == 0:
                 html = html + '</tr><tr>'
 
             html = html + '<td width=96 height=128 valign=top align=center><a class="service-grid-icon" href="%s"><img src="%s" height=64 width=64></img></a>' % (view_url, image_url)
             html = html + '<p><a class="service-grid-icon-link" href="%s">%s</a></p></td>' % (view_url, service_name)
-            i=i+1
+            i = i+1
 
         html = html + '</tr></table>'
 
@@ -61,9 +62,11 @@
         response_kwargs = {}
         response_kwargs.setdefault('content_type', self.content_type)
         return self.response_class(
-            request = request,
-            template = t,
-            **response_kwargs)
+            request=request,
+            template=t,
+            **response_kwargs
+        )
+
 
 class ServiceGraphViewOld(TemplateView):
     #  this attempt used networkx
@@ -78,14 +81,14 @@
         import matplotlib.pyplot as plt
         import nxedges
 
-        plt.figure(figsize=(10,8))
+        plt.figure(figsize=(10, 8))
 
         g = nx.DiGraph()
 
         labels = {}
         for service in Service.objects.all():
             g.add_node(service.id)
-            if len(service.name)>8:
+            if len(service.name) > 8:
                 labels[service.id] = service.name[:8] + "\n" + service.name[8:]
             else:
                 labels[service.id] = service.name
@@ -96,13 +99,14 @@
             g.add_edge(tenant.subscriber_service.id, tenant.provider_service.id)
 
         pos = nx.graphviz_layout(g)
-        nxedges.xos_draw_networkx_edges(g,pos,arrow_len=30)
-        nx.draw_networkx_nodes(g,pos,node_size=5000)
-        nx.draw_networkx_labels(g,pos,labels,font_size=12)
-        #plt.axis('off')
+        nxedges.xos_draw_networkx_edges(g, pos, arrow_len=30)
+        nx.draw_networkx_nodes(g, pos, node_size=5000)
+        nx.draw_networkx_labels(g, pos, labels, font_size=12)
+        # plt.axis('off')
         plt.savefig("/tmp/foo.png")
 
-        return HttpResponse(open("/tmp/foo.png","r").read(), content_type="image/png")
+        return HttpResponse(open("/tmp/foo.png", "r").read(), content_type="image/png")
+
 
 class ServiceGraphView(TemplateView):
     # this attempt just uses graphviz directly
@@ -115,7 +119,7 @@
         g = pgv.AGraph(directed=True)
         g.graph_attr.update(size="8,4!")
         g.graph_attr.update(dpi="100")
-        #g.graph_attr.update(nodesep="2.5")
+        # g.graph_attr.update(nodesep="2.5")
         g.graph_attr.update(overlap="false")
         g.graph_attr.update(graphdir="TB")
 
@@ -123,8 +127,8 @@
             provided_tenants = Tenant.objects.filter(provider_service=service, subscriber_service__isnull=False)
             subscribed_tenants = Tenant.objects.filter(subscriber_service=service, provider_service__isnull=False)
             if not (provided_tenants or subscribed_tenants):
-               # nodes with no edges aren't interesting
-               continue
+                # nodes with no edges aren't interesting
+                continue
             g.add_node(service.id, label=service.name)
 
         for tenant in Tenant.objects.all():
diff --git a/xos/core/xoslib/dashboards/xosDiagnostic.html b/xos/core/xoslib/dashboards/xosDiagnostic.html
new file mode 100644
index 0000000..f988d9a
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosDiagnostic.html
@@ -0,0 +1,15 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosDiagnostic.css">
+<!-- endinject -->
+
+<div id="xosDiagnostic">
+    <div ui-view></div>
+</div>
+
+
+<!-- inject:js -->
+<script src="/static/js/vendor/xosDiagnosticVendor.js"></script>
+<script src="/static/js/xosDiagnostic.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosMcordTopology.html b/xos/core/xoslib/dashboards/xosMcordTopology.html
new file mode 100644
index 0000000..163abba
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosMcordTopology.html
@@ -0,0 +1,15 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosMcordTopology.css">
+<!-- endinject -->
+
+<div id="xosMcordTopology">
+    <div ui-view></div>
+</div>
+
+
+<!-- inject:js -->
+<script src="/static/js/vendor/xosMcordTopologyVendor.js"></script>
+<script src="/static/js/xosMcordTopology.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index 5f99b61..9e46aa7 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -1246,8 +1246,13 @@
                 query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
                 if additional_query:
                     query = query + additional_query
-                statistics = statistic_list(request, meter["name"],
+                try:
+                    statistics = statistic_list(request, meter["name"],
                                         ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                except Exception as e:
+                    logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                    statistics = None
+
                 if not statistics:
                     continue
                 statistic = statistics[-1]
@@ -1398,8 +1403,13 @@
                     query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
                     if additional_query:
                         query = query + additional_query
-                    statistics = statistic_list(request, meter["name"],
+                    try:
+                        statistics = statistic_list(request, meter["name"],
                                             ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                    except Exception as e:
+                        logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                        statistics = None
+
                     if not statistics:
                         continue
                     statistic = statistics[-1]
diff --git a/xos/core/xoslib/static/css/xosDiagnostic.css b/xos/core/xoslib/static/css/xosDiagnostic.css
new file mode 100644
index 0000000..4adb559
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosDiagnostic.css
@@ -0,0 +1 @@
+[ui-view],m-cord-topology{width:100%;height:100%;display:block}line{stroke:blue;stroke-width:1}line.big{stroke-width:2}circle,rect{fill:#fff;stroke-width:1}.fabric{stroke:none;fill:#123456;fill-rule:evenodd}.fabric-container{fill:transparent;stroke:#000;stroke-width:1}.bbu{stroke:black;fill:#ff7f0e}.rru{stroke:#000;fill:#ffbb78}.rru-shadow{fill:#ffbb78;opacity:.4}.MME,.SGW,.PGW{fill:purple;stroke:#000}.bbu text,.MME text,.SGW text,.PGW text{font-size:10px;stroke-width:0;fill:#000}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosMcordTopology.css b/xos/core/xoslib/static/css/xosMcordTopology.css
new file mode 100644
index 0000000..5d7ad0e
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosMcordTopology.css
@@ -0,0 +1 @@
+#xosMcordTopology{height:700px}[ui-view],m-cord-topology{width:100%;height:100%;display:block}line{stroke:blue;stroke-width:1}line.big{stroke-width:2}circle,rect{fill:#fff;stroke-width:1}.fabric{stroke:none;fill:#123456;fill-rule:evenodd}.fabric-container{fill:transparent;stroke:#000;stroke-width:1}.bbu{stroke:black;fill:#ff7f0e}.rru{stroke:#000;fill:#ffbb78}.rru.antenna{stroke:#000;fill:brown}.rru-shadow{fill:#ffbb78;opacity:.4}.MME,.SGW,.PGW{fill:purple;stroke:#000}.bbu text,.MME text,.SGW text,.PGW text{font-size:10px;stroke-width:0;fill:#fff}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js b/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
new file mode 100644
index 0000000..9ef6d6d
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
@@ -0,0 +1,8 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function r(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function e(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,r,e,i){for(arguments.length<3&&(e=0),arguments.length<4&&(i=t.length);i>e;){var u=e+i>>>1;n(t[u],r)<0?e=u+1:i=u}return e},right:function(t,r,e,i){for(arguments.length<3&&(e=0),arguments.length<4&&(i=t.length);i>e;){var u=e+i>>>1;n(t[u],r)>0?i=u:e=u+1}return e}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var r in t)Object.defineProperty(n.prototype,r,{value:t[r],enumerable:!1})}function l(){this._=Object.create(null)}function f(n){return(n+="")===Mo||n[0]===bo?bo+n:n}function s(n){return(n+="")[0]===bo?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function v(){var n=[];for(var t in this._)n.push(s(t));return n}function g(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function _(n,t,r){return function(){var e=r.apply(t,arguments);return e===t?n:e}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var r=0,e=wo.length;e>r;++r){var i=wo[r]+t;if(i in n)return i}}function M(){}function b(){}function w(n){function t(){for(var t,e=r,i=-1,u=e.length;++i<u;)(t=e[i].on)&&t.apply(this,arguments);return n}var r=[],e=new l;return t.on=function(t,i){var u,o=e.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,r=r.slice(0,u=r.indexOf(o)).concat(r.slice(u+1)),e.remove(t)),i&&r.push(e.set(t,{on:i})),n)},t}function k(){ao.event.preventDefault()}function C(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function A(n){for(var t=new b,r=0,e=arguments.length;++r<e;)t[arguments[r]]=w(t);return t.of=function(r,e){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(r,e)}finally{ao.event=u}}},t}function S(n){return Co(n,No),n}function E(n){return"function"==typeof n?n:function(){return Ao(n,this)}}function N(n){return"function"==typeof n?n:function(){return So(n,this)}}function $(n,t){function r(){this.removeAttribute(n)}function e(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var r=t.apply(this,arguments);null==r?this.removeAttribute(n):this.setAttribute(n,r)}function a(){var r=t.apply(this,arguments);null==r?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,r)}return n=ao.ns.qualify(n),null==t?n.local?e:r:"function"==typeof t?n.local?a:o:n.local?u:i}function j(n){return n.trim().replace(/\s+/g," ")}function D(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function L(n,t){function r(){for(var r=-1;++r<i;)n[r](this,t)}function e(){for(var r=-1,e=t.apply(this,arguments);++r<i;)n[r](this,e)}n=T(n).map(R);var i=n.length;return"function"==typeof t?e:r}function R(n){var t=D(n);return function(r,e){if(i=r.classList)return e?i.add(n):i.remove(n);var i=r.getAttribute("class")||"";e?(t.lastIndex=0,t.test(i)||r.setAttribute("class",j(i+" "+n))):r.setAttribute("class",j(i.replace(t," ")))}}function O(n,t,r){function e(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,r)}function u(){var e=t.apply(this,arguments);null==e?this.style.removeProperty(n):this.style.setProperty(n,e,r)}return null==t?e:"function"==typeof t?u:i}function z(n,t){function r(){delete this[n]}function e(){this[n]=t}function i(){var r=t.apply(this,arguments);null==r?delete this[n]:this[n]=r}return null==t?r:"function"==typeof t?i:e}function q(n){function t(){var t=this.ownerDocument,r=this.namespaceURI;return r&&r!==t.documentElement.namespaceURI?t.createElementNS(r,n):t.createElement(n)}function r(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?r:t}function I(){var n=this.parentNode;n&&n.removeChild(this)}function P(n){return{__data__:n}}function U(n){return function(){return Eo(this,n)}}function F(n){return arguments.length||(n=r),function(t,r){return t&&r?n(t.__data__,r.__data__):!t-!r}}function H(n,t){for(var r=0,e=n.length;e>r;r++)for(var i,u=n[r],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,r);return n}function W(n){return Co(n,jo),n}function B(n){var t,r;return function(e,i,u){var o,a=n[u].update,c=a.length;for(u!=r&&(r=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<c;);return o}}function Y(n,t,r){function e(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=c(t,lo(arguments));e.call(this),this.addEventListener(n,this[o]=i,i.$=r),i._=t}function u(){var t,r=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var e in this)if(t=e.match(r)){var i=this[e];this.removeEventListener(t[1],i,i.$),delete this[e]}}var o="__on"+n,a=n.indexOf("."),c=Z;a>0&&(n=n.slice(0,a));var l=Do.get(n);return l&&(n=l,c=V),a?t?i:e:t?M:u}function Z(n,t){return function(r){var e=ao.event;ao.event=r,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=e}}}function V(n,t){var r=Z(n,t);return function(n){var t=this,e=n.relatedTarget;e&&(e===t||8&e.compareDocumentPosition(t))||r.call(t,n)}}function X(r){var e=".dragsuppress-"+ ++Lo,i="click"+e,u=ao.select(t(r)).on("touchmove"+e,k).on("dragstart"+e,k).on("selectstart"+e,k);if(null==To&&(To="onselectstart"in r?!1:x(r.style,"userSelect")),To){var o=n(r).style,a=o[To];o[To]="none"}return function(n){if(u.on(e,null),To&&(o[To]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){k(),t()},!0),setTimeout(t,0)}}}function K(n,r){r.changedTouches&&(r=r.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var i=e.createSVGPoint();if(0>Ro){var u=t(n);if(u.scrollX||u.scrollY){e=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=e[0][0].getScreenCTM();Ro=!(o.f||o.e),e.remove()}}return Ro?(i.x=r.pageX,i.y=r.pageY):(i.x=r.clientX,i.y=r.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[r.clientX-a.left-n.clientLeft,r.clientY-a.top-n.clientTop]}function J(){return ao.event.changedTouches[0].identifier}function Q(n){return n>0?1:0>n?-1:0}function G(n,t,r){return(t[0]-n[0])*(r[1]-n[1])-(t[1]-n[1])*(r[0]-n[0])}function nn(n){return n>1?0:-1>n?qo:Math.acos(n)}function tn(n){return n>1?Uo:-1>n?-Uo:Math.asin(n)}function rn(n){return((n=Math.exp(n))-1/n)/2}function en(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function cn(n,t,r){return this instanceof cn?(this.h=+n,this.s=+t,void(this.l=+r)):arguments.length<2?n instanceof cn?new cn(n.h,n.s,n.l):bn(""+n,wn,cn):new cn(n,t,r)}function ln(n,t,r){function e(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*e(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,r=0>r?0:r>1?1:r,o=.5>=r?r*(1+t):r+t-r*t,u=2*r-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,r){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+r)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?vn(n.l,n.a,n.b):vn((n=kn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,r)}function sn(n,t,r){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(r,Math.cos(n*=Fo)*t,Math.sin(n)*t)}function hn(n,t,r){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+r)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):kn((n=mn(n)).r,n.g,n.b):new hn(n,t,r)}function pn(n,t,r){var e=(n+16)/116,i=e+t/500,u=e-r/200;return i=gn(i)*Go,e=gn(e)*na,u=gn(u)*ta,new mn(yn(3.2404542*i-1.5371385*e-.4985314*u),yn(-.969266*i+1.8760108*e+.041556*u),yn(.0556434*i-.2040259*e+1.0572252*u))}function vn(n,t,r){return n>0?new fn(Math.atan2(r,t)*Ho,Math.sqrt(t*t+r*r),n):new fn(NaN,NaN,n)}function gn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,r){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~r)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):bn(""+n,mn,ln):new mn(n,t,r)}function _n(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return _n(n)+""}function Mn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bn(n,t,r){var e,i,u,o=0,a=0,c=0;if(e=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=e[2].split(","),e[1]){case"hsl":return r(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(An(i[0]),An(i[1]),An(i[2]))}return(u=ia.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,c=15&u,c=c<<4|c):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,c=255&u)),t(o,a,c))}function wn(n,t,r){var e,i,u=Math.min(n/=255,t/=255,r/=255),o=Math.max(n,t,r),a=o-u,c=(o+u)/2;return a?(i=.5>c?a/(o+u):a/(2-o-u),e=n==o?(t-r)/a+(r>t?6:0):t==o?(r-n)/a+2:(n-t)/a+4,e*=60):(e=NaN,i=c>0&&1>c?0:e),new cn(e,i,c)}function kn(n,t,r){n=Cn(n),t=Cn(t),r=Cn(r);var e=dn((.4124564*n+.3575761*t+.1804375*r)/Go),i=dn((.2126729*n+.7151522*t+.072175*r)/na),u=dn((.0193339*n+.119192*t+.9503041*r)/ta);return hn(116*i-16,500*(e-i),200*(i-u))}function Cn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function An(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Sn(n){return"function"==typeof n?n:function(){return n}}function En(n){return function(t,r,e){return 2===arguments.length&&"function"==typeof r&&(e=r,r=null),Nn(t,r,n,e)}}function Nn(n,t,r,e){function i(){var n,t=c.status;if(!t&&jn(c)||t>=200&&300>t||304===t){try{n=r.call(u,c)}catch(e){return void o.error.call(u,e)}o.load.call(u,n)}else o.error.call(u,c)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=i:c.onreadystatechange=function(){c.readyState>3&&i()},c.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,c)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(l=n,u):l},u.response=function(n){return r=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(lo(arguments)))}}),u.send=function(r,e,i){if(2===arguments.length&&"function"==typeof e&&(i=e,e=null),c.open(r,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var f in a)c.setRequestHeader(f,a[f]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,c),c.send(null==e?null:e),u},u.abort=function(){return c.abort(),u},ao.rebind(u,o,"on"),null==e?u:u.get($n(e))}function $n(n){return 1===n.length?function(t,r){n(null==t?r:null)}:n}function jn(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function Dn(n,t,r){var e=arguments.length;2>e&&(t=0),3>e&&(r=Date.now());var i=r+t,u={c:n,t:i,n:null};return oa?oa.n=u:ua=u,oa=u,aa||(ca=clearTimeout(ca),aa=1,la(Tn)),u}function Tn(){var n=Ln(),t=Rn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),aa=0):(aa=1,la(Tn))}function Ln(){for(var n=Date.now(),t=ua;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Rn(){for(var n,t=ua,r=1/0;t;)t.c?(t.t<r&&(r=t.t),t=(n=t).n):t=n?n.n=t.n:ua=t.n;return oa=n,r}function On(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function zn(n,t){var r=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/r}:function(n){return n*r},symbol:n}}function qn(n){var t=n.decimal,r=n.thousands,e=n.grouping,i=n.currency,u=e&&r?function(n,t){for(var i=n.length,u=[],o=0,a=e[0],c=0;i>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),u.push(n.substring(i-=a,i+a)),!((c+=a+1)>t));)a=e[o=(o+1)%e.length];return u.reverse().join(r)}:m;return function(n){var r=sa.exec(n),e=r[1]||" ",o=r[2]||">",a=r[3]||"-",c=r[4]||"",l=r[5],f=+r[6],s=r[7],h=r[8],p=r[9],v=1,g="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(l||"0"===e&&"="===o)&&(l=e="0",o="="),p){case"n":s=!0,p="g";break;case"%":v=100,d="%",p="f";break;case"p":v=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===c&&(g="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":v=-1,p="r"}"$"===c&&(g=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=ha.get(p)||In;var _=l&&s;return function(n){var r=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>v){var c=ao.formatPrefix(n,h);n=c.scale(n),r=c.symbol+d}else n*=v;n=p(n,h);var x,M,b=n.lastIndexOf(".");if(0>b){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,M=""):(x=n.substring(0,w),M=n.substring(w))}else x=n.substring(0,b),M=t+n.substring(b+1);!l&&s&&(x=u(x,1/0));var k=g.length+x.length+M.length+(_?0:i.length),C=f>k?new Array(k=f-k+1).join(e):"";return _&&(x=u(C+x,C.length?f-M.length:1/0)),i+=g,n=x+M,("<"===o?i+n+C:">"===o?C+i+n:"^"===o?C.substring(0,k>>=1)+i+n+C.substring(k):i+(_?n:C+n))+r}}}function In(n){return n+""}function Pn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Un(n,t,r){function e(t){var r=n(t),e=u(r,1);return e-t>t-r?r:e}function i(r){return t(r=n(new va(r-1)),1),r}function u(n,r){return t(n=new va(+n),r),n}function o(n,e,u){var o=i(n),a=[];if(u>1)for(;e>o;)r(o)%u||a.push(new Date(+o)),t(o,1);else for(;e>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,r){try{va=Pn;var e=new Pn;return e._=n,o(e,t,r)}finally{va=Date}}n.floor=n,n.round=e,n.ceil=i,n.offset=u,n.range=o;var c=n.utc=Fn(n);return c.floor=c,c.round=Fn(e),c.ceil=Fn(i),c.offset=Fn(u),c.range=a,n}function Fn(n){return function(t,r){try{va=Pn;var e=new Pn;return e._=t,n(e,r)._}finally{va=Date}}}function Hn(n){function t(n){function t(t){for(var r,i,u,o=[],a=-1,c=0;++a<e;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(i=da[r=n.charAt(++a)])&&(r=n.charAt(++a)),(u=E[r])&&(r=u(t,null==i?"e"===r?" ":"0":i)),o.push(r),c=a+1);return o.push(n.slice(c,a)),o.join("")}var e=n.length;return t.parse=function(t){var e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=r(e,n,t,0);if(i!=t.length)return null;"p"in e&&(e.H=e.H%12+12*e.p);var u=null!=e.Z&&va!==Pn,o=new(u?Pn:va);return"j"in e?o.setFullYear(e.y,0,e.j):"W"in e||"U"in e?("w"in e||(e.w="W"in e?1:0),o.setFullYear(e.y,0,1),o.setFullYear(e.y,0,"W"in e?(e.w+6)%7+7*e.W-(o.getDay()+5)%7:e.w+7*e.U-(o.getDay()+6)%7)):o.setFullYear(e.y,e.m,e.d),o.setHours(e.H+(e.Z/100|0),e.M+e.Z%100,e.S,e.L),u?o._:o},t.toString=function(){return n},t}function r(n,t,r,e){for(var i,u,o,a=0,c=t.length,l=r.length;c>a;){if(e>=l)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=N[o in da?t.charAt(a++):o],!u||(e=u(n,r,e))<0)return-1}else if(i!=r.charCodeAt(e++))return-1}return e}function e(n,t,r){b.lastIndex=0;var e=b.exec(t.slice(r));return e?(n.w=w.get(e[0].toLowerCase()),r+e[0].length):-1}function i(n,t,r){x.lastIndex=0;var e=x.exec(t.slice(r));return e?(n.w=M.get(e[0].toLowerCase()),r+e[0].length):-1}function u(n,t,r){A.lastIndex=0;var e=A.exec(t.slice(r));return e?(n.m=S.get(e[0].toLowerCase()),r+e[0].length):-1}function o(n,t,r){k.lastIndex=0;var e=k.exec(t.slice(r));return e?(n.m=C.get(e[0].toLowerCase()),r+e[0].length):-1}function a(n,t,e){return r(n,E.c.toString(),t,e)}function c(n,t,e){return r(n,E.x.toString(),t,e)}function l(n,t,e){return r(n,E.X.toString(),t,e)}function f(n,t,r){var e=_.get(t.slice(r,r+=2).toLowerCase());return null==e?-1:(n.p=e,r)}var s=n.dateTime,h=n.date,p=n.time,v=n.periods,g=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function r(n){try{va=Pn;var t=new va;return t._=n,e(t)}finally{va=Date}}var e=t(n);return r.parse=function(n){try{va=Pn;var t=e.parse(n);return t&&t._}finally{va=Date}},r.toString=e.toString,r},t.multi=t.utc.multi=lt;var _=ao.map(),x=Bn(g),M=Yn(g),b=Bn(d),w=Yn(d),k=Bn(y),C=Yn(y),A=Bn(m),S=Yn(m);v.forEach(function(n,t){_.set(n.toLowerCase(),t)});var E={a:function(n){return d[n.getDay()]},A:function(n){return g[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Wn(n.getDate(),t,2)},e:function(n,t){return Wn(n.getDate(),t,2)},H:function(n,t){return Wn(n.getHours(),t,2)},I:function(n,t){return Wn(n.getHours()%12||12,t,2)},j:function(n,t){return Wn(1+pa.dayOfYear(n),t,3)},L:function(n,t){return Wn(n.getMilliseconds(),t,3)},m:function(n,t){return Wn(n.getMonth()+1,t,2)},M:function(n,t){return Wn(n.getMinutes(),t,2)},p:function(n){return v[+(n.getHours()>=12)]},S:function(n,t){return Wn(n.getSeconds(),t,2)},U:function(n,t){return Wn(pa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Wn(pa.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Wn(n.getFullYear()%100,t,2)},Y:function(n,t){return Wn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},N={a:e,A:i,b:u,B:o,c:a,d:tt,e:tt,H:et,I:et,j:rt,L:ot,m:nt,M:it,p:f,S:ut,U:Vn,w:Zn,W:Xn,x:c,X:l,y:Jn,Y:Kn,Z:Qn,"%":ct};return t}function Wn(n,t,r){var e=0>n?"-":"",i=(e?-n:n)+"",u=i.length;return e+(r>u?new Array(r-u+1).join(t)+i:i)}function Bn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Yn(n){for(var t=new l,r=-1,e=n.length;++r<e;)t.set(n[r].toLowerCase(),r);return t}function Zn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+1));return e?(n.w=+e[0],r+e[0].length):-1}function Vn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r));return e?(n.U=+e[0],r+e[0].length):-1}function Xn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r));return e?(n.W=+e[0],r+e[0].length):-1}function Kn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+4));return e?(n.y=+e[0],r+e[0].length):-1}function Jn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.y=Gn(+e[0]),r+e[0].length):-1}function Qn(n,t,r){return/^[+-]\d{4}$/.test(t=t.slice(r,r+5))?(n.Z=-t,r+5):-1}function Gn(n){return n+(n>68?1900:2e3)}function nt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.m=e[0]-1,r+e[0].length):-1}function tt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.d=+e[0],r+e[0].length):-1}function rt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+3));return e?(n.j=+e[0],r+e[0].length):-1}function et(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.H=+e[0],r+e[0].length):-1}function it(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.M=+e[0],r+e[0].length):-1}function ut(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.S=+e[0],r+e[0].length):-1}function ot(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+3));return e?(n.L=+e[0],r+e[0].length):-1}function at(n){var t=n.getTimezoneOffset(),r=t>0?"-":"+",e=xo(t)/60|0,i=xo(t)%60;return r+Wn(e,"0",2)+Wn(i,"0",2)}function ct(n,t,r){ma.lastIndex=0;var e=ma.exec(t.slice(r,r+1));return e?r+e[0].length:-1}function lt(n){for(var t=n.length,r=-1;++r<t;)n[r][0]=this(n[r][0]);return function(t){for(var r=0,e=n[r];!e[1](t);)e=n[++r];return e[0](t)}}function ft(){}function st(n,t,r){var e=r.s=n+t,i=e-n,u=e-i;r.t=n-u+(t-i)}function ht(n,t){n&&ba.hasOwnProperty(n.type)&&ba[n.type](n,t)}function pt(n,t,r){var e,i=-1,u=n.length-r;for(t.lineStart();++i<u;)e=n[i],t.point(e[0],e[1],e[2]);t.lineEnd()}function vt(n,t){var r=-1,e=n.length;for(t.polygonStart();++r<e;)pt(n[r],t,1);t.polygonEnd()}function gt(){function n(n,t){n*=Fo,t=t*Fo/2+qo/4;var r=n-e,o=r>=0?1:-1,a=o*r,c=Math.cos(t),l=Math.sin(t),f=u*l,s=i*c+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),e=n,i=c,u=l}var t,r,e,i,u;Ca.point=function(o,a){Ca.point=n,e=(t=o)*Fo,i=Math.cos(a=(r=a)*Fo/2+qo/4),u=Math.sin(a)},Ca.lineEnd=function(){n(t,r)}}function dt(n){var t=n[0],r=n[1],e=Math.cos(r);return[e*Math.cos(t),e*Math.sin(t),Math.sin(r)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function _t(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Mt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function bt(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Oo&&xo(n[1]-t[1])<Oo}function kt(n,t){n*=Fo;var r=Math.cos(t*=Fo);Ct(r*Math.cos(n),r*Math.sin(n),Math.sin(t))}function Ct(n,t,r){++Aa,Ea+=(n-Ea)/Aa,Na+=(t-Na)/Aa,$a+=(r-$a)/Aa}function At(){function n(n,i){n*=Fo;var u=Math.cos(i*=Fo),o=u*Math.cos(n),a=u*Math.sin(n),c=Math.sin(i),l=Math.atan2(Math.sqrt((l=r*c-e*a)*l+(l=e*o-t*c)*l+(l=t*a-r*o)*l),t*o+r*a+e*c);Sa+=l,ja+=l*(t+(t=o)),Da+=l*(r+(r=a)),Ta+=l*(e+(e=c)),Ct(t,r,e)}var t,r,e;za.point=function(i,u){i*=Fo;var o=Math.cos(u*=Fo);t=o*Math.cos(i),r=o*Math.sin(i),e=Math.sin(u),za.point=n,Ct(t,r,e)}}function St(){za.point=kt}function Et(){function n(n,t){n*=Fo;var r=Math.cos(t*=Fo),o=r*Math.cos(n),a=r*Math.sin(n),c=Math.sin(t),l=i*c-u*a,f=u*o-e*c,s=e*a-i*o,h=Math.sqrt(l*l+f*f+s*s),p=e*o+i*a+u*c,v=h&&-nn(p)/h,g=Math.atan2(h,p);La+=v*l,Ra+=v*f,Oa+=v*s,Sa+=g,ja+=g*(e+(e=o)),Da+=g*(i+(i=a)),Ta+=g*(u+(u=c)),Ct(e,i,u)}var t,r,e,i,u;za.point=function(o,a){t=o,r=a,za.point=n,o*=Fo;var c=Math.cos(a*=Fo);e=c*Math.cos(o),i=c*Math.sin(o),u=Math.sin(a),Ct(e,i,u)},za.lineEnd=function(){n(t,r),za.lineEnd=St,za.point=kt}}function Nt(n,t){function r(r,e){return r=n(r,e),t(r[0],r[1])}return n.invert&&t.invert&&(r.invert=function(r,e){return r=t.invert(r,e),r&&n.invert(r[0],r[1])}),r}function $t(){return!0}function jt(n,t,r,e,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,r=n[0],e=n[t];if(wt(r,e)){i.lineStart();for(var a=0;t>a;++a)i.point((r=n[a])[0],r[1]);return void i.lineEnd()}var c=new Tt(r,n,null,!0),l=new Tt(r,null,c,!1);c.o=l,u.push(c),o.push(l),c=new Tt(e,n,null,!1),l=new Tt(e,null,c,!0),c.o=l,u.push(c),o.push(l)}}),o.sort(t),Dt(u),Dt(o),u.length){for(var a=0,c=r,l=o.length;l>a;++a)o[a].e=c=!c;for(var f,s,h=u[0];;){for(var p=h,v=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(v)for(var a=0,l=f.length;l>a;++a)i.point((s=f[a])[0],s[1]);else e(p.x,p.n.x,1,i);p=p.n}else{if(v){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else e(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,v=!v}while(!p.v);i.lineEnd()}}}function Dt(n){if(t=n.length){for(var t,r,e=0,i=n[0];++e<t;)i.n=r=n[e],r.p=i,i=r;i.n=r=n[0],r.p=i}}function Tt(n,t,r,e){this.x=n,this.z=t,this.o=r,this.e=e,this.v=!1,this.n=this.p=null}function Lt(n,t,r,e){return function(i,u){function o(t,r){var e=i(t,r);n(t=e[0],r=e[1])&&u.point(t,r)}function a(n,t){var r=i(n,t);d.point(r[0],r[1])}function c(){m.point=a,d.lineStart()}function l(){m.point=o,d.lineEnd()}function f(n,t){g.push([n,t]);var r=i(n,t);x.point(r[0],r[1])}function s(){x.lineStart(),g=[]}function h(){f(g[0][0],g[0][1]),x.lineEnd();var n,t=x.clean(),r=_.buffer(),e=r.length;if(g.pop(),v.push(g),g=null,e)if(1&t){n=r[0];var i,e=n.length-1,o=-1;if(e>0){for(M||(u.polygonStart(),M=!0),u.lineStart();++o<e;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else e>1&&2&t&&r.push(r.pop().concat(r.shift())),p.push(r.filter(Rt))}var p,v,g,d=t(u),y=i.invert(e[0],e[1]),m={point:o,lineStart:c,lineEnd:l,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],v=[]},polygonEnd:function(){m.point=o,m.lineStart=c,m.lineEnd=l,p=ao.merge(p);var n=Ut(y,v);p.length?(M||(u.polygonStart(),M=!0),jt(p,zt,n,r,u)):n&&(M||(u.polygonStart(),M=!0),u.lineStart(),r(null,null,1,u),u.lineEnd()),M&&(u.polygonEnd(),M=!1),p=v=null},sphere:function(){u.polygonStart(),u.lineStart(),r(null,null,1,u),u.lineEnd(),u.polygonEnd()}},_=Ot(),x=t(_),M=!1;return m}}function Rt(n){return n.length>1}function Ot(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,r){n.push([t,r])},lineEnd:M,buffer:function(){var r=t;return t=[],n=null,r},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function zt(n,t){return((n=n.x)[0]<0?n[1]-Uo-Oo:Uo-n[1])-((t=t.x)[0]<0?t[1]-Uo-Oo:Uo-t[1])}function qt(n){var t,r=NaN,e=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?qo:-qo,c=xo(u-r);xo(c-qo)<Oo?(n.point(r,e=(e+o)/2>0?Uo:-Uo),n.point(i,e),n.lineEnd(),n.lineStart(),n.point(a,e),n.point(u,e),t=0):i!==a&&c>=qo&&(xo(r-i)<Oo&&(r-=i*Oo),xo(u-a)<Oo&&(u-=a*Oo),e=It(r,e,u,o),n.point(i,e),n.lineEnd(),n.lineStart(),n.point(a,e),t=0),n.point(r=u,e=o),i=a},lineEnd:function(){n.lineEnd(),r=e=NaN},clean:function(){return 2-t}}}function It(n,t,r,e){var i,u,o=Math.sin(n-r);return xo(o)>Oo?Math.atan((Math.sin(t)*(u=Math.cos(e))*Math.sin(r)-Math.sin(e)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+e)/2}function Pt(n,t,r,e){var i;if(null==n)i=r*Uo,e.point(-qo,i),e.point(0,i),e.point(qo,i),e.point(qo,0),e.point(qo,-i),e.point(0,-i),e.point(-qo,-i),e.point(-qo,0),e.point(-qo,i);else if(xo(n[0]-t[0])>Oo){var u=n[0]<t[0]?qo:-qo;i=r*u/2,e.point(-u,i),e.point(0,i),e.point(u,i)}else e.point(t[0],t[1])}function Ut(n,t){var r=n[0],e=n[1],i=[Math.sin(r),-Math.cos(r),0],u=0,o=0;ka.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],f=l.length;if(f)for(var s=l[0],h=s[0],p=s[1]/2+qo/4,v=Math.sin(p),g=Math.cos(p),d=1;;){d===f&&(d=0),n=l[d];var y=n[0],m=n[1]/2+qo/4,_=Math.sin(m),x=Math.cos(m),M=y-h,b=M>=0?1:-1,w=b*M,k=w>qo,C=v*_;if(ka.add(Math.atan2(C*b*Math.sin(w),g*x+C*Math.cos(w))),u+=k?M+b*Io:M,k^h>=r^y>=r){var A=mt(dt(s),dt(n));Mt(A);var S=mt(i,A);Mt(S);var E=(k^M>=0?-1:1)*tn(S[2]);(e>E||e===E&&(A[0]||A[1]))&&(o+=k^M>=0?1:-1)}if(!d++)break;h=y,v=_,g=x,s=n}}return(-Oo>u||Oo>u&&0>ka)^1&o}function Ft(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function r(n){var r,u,c,l,f;return{lineStart:function(){l=c=!1,f=1},point:function(s,h){var p,v=[s,h],g=t(s,h),d=o?g?0:i(s,h):g?i(s+(0>s?qo:-qo),h):0;if(!r&&(l=c=g)&&n.lineStart(),g!==c&&(p=e(r,v),(wt(r,p)||wt(v,p))&&(v[0]+=Oo,v[1]+=Oo,g=t(v[0],v[1]))),g!==c)f=0,g?(n.lineStart(),p=e(v,r),n.point(p[0],p[1])):(p=e(r,v),n.point(p[0],p[1]),n.lineEnd()),r=p;else if(a&&r&&o^g){var y;d&u||!(y=e(v,r,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!g||r&&wt(r,v)||n.point(v[0],v[1]),r=v,c=g,u=d},lineEnd:function(){c&&n.lineEnd(),r=null},clean:function(){return f|(l&&c)<<1}}}function e(n,t,r){var e=dt(n),i=dt(t),o=[1,0,0],a=mt(e,i),c=yt(a,a),l=a[0],f=c-l*l;if(!f)return!r&&n;var s=u*c/f,h=-u*l/f,p=mt(o,a),v=xt(o,s),g=xt(a,h);_t(v,g);var d=p,y=yt(v,d),m=yt(d,d),_=y*y-m*(yt(v,v)-1);if(!(0>_)){var x=Math.sqrt(_),M=xt(d,(-y-x)/m);if(_t(M,v),M=bt(M),!r)return M;var b,w=n[0],k=t[0],C=n[1],A=t[1];w>k&&(b=w,w=k,k=b);var S=k-w,E=xo(S-qo)<Oo,N=E||Oo>S;if(!E&&C>A&&(b=C,C=A,A=b),N?E?C+A>0^M[1]<(xo(M[0]-w)<Oo?C:A):C<=M[1]&&M[1]<=A:S>qo^(w<=M[0]&&M[0]<=k)){var $=xt(d,(-y+x)/m);return _t($,v),[M,bt($)]}}}function i(t,r){var e=o?n:qo-n,i=0;return-e>t?i|=1:t>e&&(i|=2),-e>r?i|=4:r>e&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Oo,c=gr(n,6*Fo);return Lt(t,r,c,o?[0,-n]:[-qo,n-qo])}function Ht(n,t,r,e){return function(i){var u,o=i.a,a=i.b,c=o.x,l=o.y,f=a.x,s=a.y,h=0,p=1,v=f-c,g=s-l;if(u=n-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}if(u=t-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:c+h*v,y:l+h*g}),1>p&&(i.b={x:c+p*v,y:l+p*g}),i}}}}}}function Wt(n,t,r,e){function i(e,i){return xo(e[0]-n)<Oo?i>0?0:3:xo(e[0]-r)<Oo?i>0?2:1:xo(e[1]-t)<Oo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var r=i(n,1),e=i(t,1);return r!==e?r-e:0===r?t[1]-n[1]:1===r?n[0]-t[0]:2===r?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,r=d.length,e=n[1],i=0;r>i;++i)for(var u,o=1,a=d[i],c=a.length,l=a[0];c>o;++o)u=a[o],l[1]<=e?u[1]>e&&G(l,u,n)>0&&++t:u[1]<=e&&G(l,u,n)<0&&--t,l=u;return 0!==t}function l(u,a,c,l){var f=0,s=0;if(null==u||(f=i(u,c))!==(s=i(a,c))||o(u,a)<0^c>0){do l.point(0===f||3===f?n:r,f>1?e:t);while((f=(f+c+4)%4)!==s)}else l.point(a[0],a[1])}function f(i,u){return i>=n&&r>=i&&u>=t&&e>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){N.point=v,d&&d.push(y=[]),k=!0,w=!1,M=b=NaN}function p(){g&&(v(m,_),x&&w&&S.rejoin(),g.push(S.buffer())),N.point=s,w&&a.lineEnd()}function v(n,t){n=Math.max(-Ia,Math.min(Ia,n)),t=Math.max(-Ia,Math.min(Ia,t));var r=f(n,t);if(d&&y.push([n,t]),k)m=n,_=t,x=r,k=!1,r&&(a.lineStart(),a.point(n,t));else if(r&&w)a.point(n,t);else{var e={a:{x:M,y:b},b:{x:n,y:t}};E(e)?(w||(a.lineStart(),a.point(e.a.x,e.a.y)),a.point(e.b.x,e.b.y),r||a.lineEnd(),C=!1):r&&(a.lineStart(),a.point(n,t),C=!1)}M=n,b=t,w=r}var g,d,y,m,_,x,M,b,w,k,C,A=a,S=Ot(),E=Ht(n,t,r,e),N={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=S,g=[],d=[],C=!0},polygonEnd:function(){a=A,g=ao.merge(g);var t=c([n,e]),r=C&&t,i=g.length;(r||i)&&(a.polygonStart(),r&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),i&&jt(g,u,t,l,a),a.polygonEnd()),g=d=y=null}};return N}}function Bt(n){var t=0,r=qo/3,e=ar(n),i=e(t,r);return i.parallels=function(n){return arguments.length?e(t=n[0]*qo/180,r=n[1]*qo/180):[t/qo*180,r/qo*180]},i}function Yt(n,t){function r(n,t){var r=Math.sqrt(u-2*i*Math.sin(t))/i;return[r*Math.sin(n*=i),o-r*Math.cos(n)]}var e=Math.sin(n),i=(e+Math.sin(t))/2,u=1+e*(2*i-e),o=Math.sqrt(u)/i;return r.invert=function(n,t){var r=o-t;return[Math.atan2(n,r)/i,tn((u-(n*n+r*r)*i*i)/(2*i))]},r}function Zt(){function n(n,t){Ua+=i*n-e*t,e=n,i=t}var t,r,e,i;Ya.point=function(u,o){Ya.point=n,t=e=u,r=i=o},Ya.lineEnd=function(){n(t,r)}}function Vt(n,t){Fa>n&&(Fa=n),n>Wa&&(Wa=n),Ha>t&&(Ha=t),t>Ba&&(Ba=t)}function Xt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=r}function r(n,t){o.push("L",n,",",t)}function e(){a.point=n}function i(){o.push("Z")}var u=Kt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:e,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=e,a.point=n},pointRadius:function(n){return u=Kt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Kt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Jt(n,t){Ea+=n,Na+=t,++$a}function Qt(){function n(n,e){var i=n-t,u=e-r,o=Math.sqrt(i*i+u*u);ja+=o*(t+n)/2,Da+=o*(r+e)/2,Ta+=o,Jt(t=n,r=e)}var t,r;Va.point=function(e,i){Va.point=n,Jt(t=e,r=i)}}function Gt(){Va.point=Jt}function nr(){function n(n,t){var r=n-e,u=t-i,o=Math.sqrt(r*r+u*u);ja+=o*(e+n)/2,Da+=o*(i+t)/2,Ta+=o,o=i*n-e*t,La+=o*(e+n),Ra+=o*(i+t),Oa+=3*o,Jt(e=n,i=t)}var t,r,e,i;Va.point=function(u,o){Va.point=n,Jt(t=e=u,r=i=o)},Va.lineEnd=function(){n(t,r)}}function tr(n){function t(t,r){n.moveTo(t+o,r),n.arc(t,r,o,0,Io)}function r(t,r){n.moveTo(t,r),a.point=e}function e(t,r){n.lineTo(t,r)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=r},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:M};return a}function rr(n){function t(n){return(a?e:r)(n)}function r(t){return ur(t,function(r,e){r=n(r,e),t.point(r[0],r[1])})}function e(t){function r(r,e){r=n(r,e),t.point(r[0],r[1])}function e(){_=NaN,k.point=u,t.lineStart()}function u(r,e){var u=dt([r,e]),o=n(r,e);i(_,x,m,M,b,w,_=o[0],x=o[1],m=r,M=u[0],b=u[1],w=u[2],a,t),t.point(_,x)}function o(){k.point=r,t.lineEnd()}function c(){
+e(),k.point=l,k.lineEnd=f}function l(n,t){u(s=n,h=t),p=_,v=x,g=M,d=b,y=w,k.point=u}function f(){i(_,x,m,M,b,w,p,v,s,g,d,y,a,t),k.lineEnd=o,o()}var s,h,p,v,g,d,y,m,_,x,M,b,w,k={point:r,lineStart:e,lineEnd:o,polygonStart:function(){t.polygonStart(),k.lineStart=c},polygonEnd:function(){t.polygonEnd(),k.lineStart=e}};return k}function i(t,r,e,a,c,l,f,s,h,p,v,g,d,y){var m=f-t,_=s-r,x=m*m+_*_;if(x>4*u&&d--){var M=a+p,b=c+v,w=l+g,k=Math.sqrt(M*M+b*b+w*w),C=Math.asin(w/=k),A=xo(xo(w)-1)<Oo||xo(e-h)<Oo?(e+h)/2:Math.atan2(b,M),S=n(A,C),E=S[0],N=S[1],$=E-t,j=N-r,D=_*$-m*j;(D*D/x>u||xo((m*$+_*j)/x-.5)>.3||o>a*p+c*v+l*g)&&(i(t,r,e,a,c,l,E,N,A,M/=k,b/=k,w,d,y),y.point(E,N),i(E,N,A,M,b,w,f,s,h,p,v,g,d,y))}}var u=.5,o=Math.cos(30*Fo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function er(n){var t=rr(function(t,r){return n([t*Ho,r*Ho])});return function(n){return cr(t(n))}}function ir(n){this.stream=n}function ur(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function or(n){return ar(function(){return n})()}function ar(n){function t(n){return n=a(n[0]*Fo,n[1]*Fo),[n[0]*h+c,l-n[1]*h]}function r(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Ho,n[1]*Ho]}function e(){a=Nt(o=sr(y,_,x),u);var n=u(g,d);return c=p-n[0]*h,l=v+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,c,l,f,s=rr(function(n,t){return n=u(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,p=480,v=250,g=0,d=0,y=0,_=0,x=0,M=qa,b=m,w=null,k=null;return t.stream=function(n){return f&&(f.valid=!1),f=cr(M(o,s(b(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(M=null==n?(w=n,qa):Ft((w=+n)*Fo),i()):w},t.clipExtent=function(n){return arguments.length?(k=n,b=n?Wt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):k},t.scale=function(n){return arguments.length?(h=+n,e()):h},t.translate=function(n){return arguments.length?(p=+n[0],v=+n[1],e()):[p,v]},t.center=function(n){return arguments.length?(g=n[0]%360*Fo,d=n[1]%360*Fo,e()):[g*Ho,d*Ho]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Fo,_=n[1]%360*Fo,x=n.length>2?n[2]%360*Fo:0,e()):[y*Ho,_*Ho,x*Ho]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&r,e()}}function cr(n){return ur(n,function(t,r){n.point(t*Fo,r*Fo)})}function lr(n,t){return[n,t]}function fr(n,t){return[n>qo?n-Io:-qo>n?n+Io:n,t]}function sr(n,t,r){return n?t||r?Nt(pr(n),vr(t,r)):pr(n):t||r?vr(t,r):fr}function hr(n){return function(t,r){return t+=n,[t>qo?t-Io:-qo>t?t+Io:t,r]}}function pr(n){var t=hr(n);return t.invert=hr(-n),t}function vr(n,t){function r(n,t){var r=Math.cos(t),a=Math.cos(n)*r,c=Math.sin(n)*r,l=Math.sin(t),f=l*e+a*i;return[Math.atan2(c*u-f*o,a*e-l*i),tn(f*u+c*o)]}var e=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return r.invert=function(n,t){var r=Math.cos(t),a=Math.cos(n)*r,c=Math.sin(n)*r,l=Math.sin(t),f=l*u-c*o;return[Math.atan2(c*u+l*o,a*e+f*i),tn(f*e-a*i)]},r}function gr(n,t){var r=Math.cos(n),e=Math.sin(n);return function(i,u,o,a){var c=o*t;null!=i?(i=dr(r,i),u=dr(r,u),(o>0?u>i:i>u)&&(i+=o*Io)):(i=n+o*Io,u=n-.5*c);for(var l,f=i;o>0?f>u:u>f;f-=c)a.point((l=bt([r,-e*Math.cos(f),-e*Math.sin(f)]))[0],l[1])}}function dr(n,t){var r=dt(t);r[0]-=n,Mt(r);var e=nn(-r[1]);return((-r[2]<0?-e:e)+2*Math.PI-Oo)%(2*Math.PI)}function yr(n,t,r){var e=ao.range(n,t-Oo,r).concat(t);return function(n){return e.map(function(t){return[n,t]})}}function mr(n,t,r){var e=ao.range(n,t-Oo,r).concat(t);return function(n){return e.map(function(t){return[t,n]})}}function _r(n){return n.source}function xr(n){return n.target}function Mr(n,t,r,e){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(e),a=Math.sin(e),c=i*Math.cos(n),l=i*Math.sin(n),f=o*Math.cos(r),s=o*Math.sin(r),h=2*Math.asin(Math.sqrt(on(e-t)+i*o*on(r-n))),p=1/Math.sin(h),v=h?function(n){var t=Math.sin(n*=h)*p,r=Math.sin(h-n)*p,e=r*c+t*f,i=r*l+t*s,o=r*u+t*a;return[Math.atan2(i,e)*Ho,Math.atan2(o,Math.sqrt(e*e+i*i))*Ho]}:function(){return[n*Ho,t*Ho]};return v.distance=h,v}function br(){function n(n,i){var u=Math.sin(i*=Fo),o=Math.cos(i),a=xo((n*=Fo)-t),c=Math.cos(a);Xa+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=e*u-r*o*c)*a),r*u+e*o*c),t=n,r=u,e=o}var t,r,e;Ka.point=function(i,u){t=i*Fo,r=Math.sin(u*=Fo),e=Math.cos(u),Ka.point=n},Ka.lineEnd=function(){Ka.point=Ka.lineEnd=M}}function wr(n,t){function r(t,r){var e=Math.cos(t),i=Math.cos(r),u=n(e*i);return[u*i*Math.sin(t),u*Math.sin(r)]}return r.invert=function(n,r){var e=Math.sqrt(n*n+r*r),i=t(e),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,e*o),Math.asin(e&&r*u/e)]},r}function kr(n,t){function r(n,t){o>0?-Uo+Oo>t&&(t=-Uo+Oo):t>Uo-Oo&&(t=Uo-Oo);var r=o/Math.pow(i(t),u);return[r*Math.sin(u*n),o-r*Math.cos(u*n)]}var e=Math.cos(n),i=function(n){return Math.tan(qo/4+n/2)},u=n===t?Math.sin(n):Math.log(e/Math.cos(t))/Math.log(i(t)/i(n)),o=e*Math.pow(i(n),u)/u;return u?(r.invert=function(n,t){var r=o-t,e=Q(u)*Math.sqrt(n*n+r*r);return[Math.atan2(n,r)/u,2*Math.atan(Math.pow(o/e,1/u))-Uo]},r):Ar}function Cr(n,t){function r(n,t){var r=u-t;return[r*Math.sin(i*n),u-r*Math.cos(i*n)]}var e=Math.cos(n),i=n===t?Math.sin(n):(e-Math.cos(t))/(t-n),u=e/i+n;return xo(i)<Oo?lr:(r.invert=function(n,t){var r=u-t;return[Math.atan2(n,r)/i,u-Q(i)*Math.sqrt(n*n+r*r)]},r)}function Ar(n,t){return[n,Math.log(Math.tan(qo/4+t/2))]}function Sr(n){var t,r=or(n),e=r.scale,i=r.translate,u=r.clipExtent;return r.scale=function(){var n=e.apply(r,arguments);return n===r?t?r.clipExtent(null):r:n},r.translate=function(){var n=i.apply(r,arguments);return n===r?t?r.clipExtent(null):r:n},r.clipExtent=function(n){var o=u.apply(r,arguments);if(o===r){if(t=null==n){var a=qo*e(),c=i();u([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},r.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qo/4+t/2)),-n]}function Nr(n){return n[0]}function $r(n){return n[1]}function jr(n){for(var t=n.length,r=[0,1],e=2,i=2;t>i;i++){for(;e>1&&G(n[r[e-2]],n[r[e-1]],n[i])<=0;)--e;r[e++]=i}return r.slice(0,e)}function Dr(n,t){return n[0]-t[0]||n[1]-t[1]}function Tr(n,t,r){return(r[0]-t[0])*(n[1]-t[1])<(r[1]-t[1])*(n[0]-t[0])}function Lr(n,t,r,e){var i=n[0],u=r[0],o=t[0]-i,a=e[0]-u,c=n[1],l=r[1],f=t[1]-c,s=e[1]-l,h=(a*(c-l)-s*(i-u))/(s*o-a*f);return[i+h*o,c+h*f]}function Rr(n){var t=n[0],r=n[n.length-1];return!(t[0]-r[0]||t[1]-r[1])}function Or(){ee(this),this.edge=this.site=this.circle=null}function zr(n){var t=cc.pop()||new Or;return t.site=n,t}function qr(n){Vr(n),uc.remove(n),cc.push(n),ee(n)}function Ir(n){var t=n.circle,r=t.x,e=t.cy,i={x:r,y:e},u=n.P,o=n.N,a=[n];qr(n);for(var c=u;c.circle&&xo(r-c.circle.x)<Oo&&xo(e-c.circle.cy)<Oo;)u=c.P,a.unshift(c),qr(c),c=u;a.unshift(c),Vr(c);for(var l=o;l.circle&&xo(r-l.circle.x)<Oo&&xo(e-l.circle.cy)<Oo;)o=l.N,a.push(l),qr(l),l=o;a.push(l),Vr(l);var f,s=a.length;for(f=1;s>f;++f)l=a[f],c=a[f-1],ne(l.edge,c.site,l.site,i);c=a[0],l=a[s-1],l.edge=Qr(c.site,l.site,null,i),Zr(c),Zr(l)}function Pr(n){for(var t,r,e,i,u=n.x,o=n.y,a=uc._;a;)if(e=Ur(a,o)-u,e>Oo)a=a.L;else{if(i=u-Fr(a,o),!(i>Oo)){e>-Oo?(t=a.P,r=a):i>-Oo?(t=a,r=a.N):t=r=a;break}if(!a.R){t=a;break}a=a.R}var c=zr(n);if(uc.insert(t,c),t||r){if(t===r)return Vr(t),r=zr(t.site),uc.insert(c,r),c.edge=r.edge=Qr(t.site,c.site),Zr(t),void Zr(r);if(!r)return void(c.edge=Qr(t.site,c.site));Vr(t),Vr(r);var l=t.site,f=l.x,s=l.y,h=n.x-f,p=n.y-s,v=r.site,g=v.x-f,d=v.y-s,y=2*(h*d-p*g),m=h*h+p*p,_=g*g+d*d,x={x:(d*m-p*_)/y+f,y:(h*_-g*m)/y+s};ne(r.edge,l,v,x),c.edge=Qr(l,n,null,x),r.edge=Qr(n,v,null,x),Zr(t),Zr(r)}}function Ur(n,t){var r=n.site,e=r.x,i=r.y,u=i-t;if(!u)return e;var o=n.P;if(!o)return-(1/0);r=o.site;var a=r.x,c=r.y,l=c-t;if(!l)return a;var f=a-e,s=1/u-1/l,h=f/l;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*l)-c+l/2+i-u/2)))/s+e:(e+a)/2}function Fr(n,t){var r=n.N;if(r)return Ur(r,t);var e=n.site;return e.y===t?e.x:1/0}function Hr(n){this.site=n,this.edges=[]}function Wr(n){for(var t,r,e,i,u,o,a,c,l,f,s=n[0][0],h=n[1][0],p=n[0][1],v=n[1][1],g=ic,d=g.length;d--;)if(u=g[d],u&&u.prepare())for(a=u.edges,c=a.length,o=0;c>o;)f=a[o].end(),e=f.x,i=f.y,l=a[++o%c].start(),t=l.x,r=l.y,(xo(e-t)>Oo||xo(i-r)>Oo)&&(a.splice(o,0,new te(Gr(u.site,f,xo(e-s)<Oo&&v-i>Oo?{x:s,y:xo(t-s)<Oo?r:v}:xo(i-v)<Oo&&h-e>Oo?{x:xo(r-v)<Oo?t:h,y:v}:xo(e-h)<Oo&&i-p>Oo?{x:h,y:xo(t-h)<Oo?r:p}:xo(i-p)<Oo&&e-s>Oo?{x:xo(r-p)<Oo?t:s,y:p}:null),u.site,null)),++c)}function Br(n,t){return t.angle-n.angle}function Yr(){ee(this),this.x=this.y=this.arc=this.site=this.cy=null}function Zr(n){var t=n.P,r=n.N;if(t&&r){var e=t.site,i=n.site,u=r.site;if(e!==u){var o=i.x,a=i.y,c=e.x-o,l=e.y-a,f=u.x-o,s=u.y-a,h=2*(c*s-l*f);if(!(h>=-zo)){var p=c*c+l*l,v=f*f+s*s,g=(s*p-l*v)/h,d=(c*v-f*p)/h,s=d+a,y=lc.pop()||new Yr;y.arc=n,y.site=i,y.x=g+o,y.y=s+Math.sqrt(g*g+d*d),y.cy=s,n.circle=y;for(var m=null,_=ac._;_;)if(y.y<_.y||y.y===_.y&&y.x<=_.x){if(!_.L){m=_.P;break}_=_.L}else{if(!_.R){m=_;break}_=_.R}ac.insert(m,y),m||(oc=y)}}}}function Vr(n){var t=n.circle;t&&(t.P||(oc=t.N),ac.remove(t),lc.push(t),ee(t),n.circle=null)}function Xr(n){for(var t,r=ec,e=Ht(n[0][0],n[0][1],n[1][0],n[1][1]),i=r.length;i--;)t=r[i],(!Kr(t,n)||!e(t)||xo(t.a.x-t.b.x)<Oo&&xo(t.a.y-t.b.y)<Oo)&&(t.a=t.b=null,r.splice(i,1))}function Kr(n,t){var r=n.b;if(r)return!0;var e,i,u=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,v=s.x,g=s.y,d=(h+v)/2,y=(p+g)/2;if(g===p){if(o>d||d>=a)return;if(h>v){if(u){if(u.y>=l)return}else u={x:d,y:c};r={x:d,y:l}}else{if(u){if(u.y<c)return}else u={x:d,y:l};r={x:d,y:c}}}else if(e=(h-v)/(g-p),i=y-e*d,-1>e||e>1)if(h>v){if(u){if(u.y>=l)return}else u={x:(c-i)/e,y:c};r={x:(l-i)/e,y:l}}else{if(u){if(u.y<c)return}else u={x:(l-i)/e,y:l};r={x:(c-i)/e,y:c}}else if(g>p){if(u){if(u.x>=a)return}else u={x:o,y:e*o+i};r={x:a,y:e*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:e*a+i};r={x:o,y:e*o+i}}return n.a=u,n.b=r,!0}function Jr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Qr(n,t,r,e){var i=new Jr(n,t);return ec.push(i),r&&ne(i,n,t,r),e&&ne(i,t,n,e),ic[n.i].edges.push(new te(i,n,t)),ic[t.i].edges.push(new te(i,t,n)),i}function Gr(n,t,r){var e=new Jr(n,null);return e.a=t,e.b=r,ec.push(e),e}function ne(n,t,r,e){n.a||n.b?n.l===r?n.b=e:n.a=e:(n.a=e,n.l=t,n.r=r)}function te(n,t,r){var e=n.a,i=n.b;this.edge=n,this.site=t,this.angle=r?Math.atan2(r.y-t.y,r.x-t.x):n.l===t?Math.atan2(i.x-e.x,e.y-i.y):Math.atan2(e.x-i.x,i.y-e.y)}function re(){this._=null}function ee(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ie(n,t){var r=t,e=t.R,i=r.U;i?i.L===r?i.L=e:i.R=e:n._=e,e.U=i,r.U=e,r.R=e.L,r.R&&(r.R.U=r),e.L=r}function ue(n,t){var r=t,e=t.L,i=r.U;i?i.L===r?i.L=e:i.R=e:n._=e,e.U=i,r.U=e,r.L=e.R,r.L&&(r.L.U=r),e.R=r}function oe(n){for(;n.L;)n=n.L;return n}function ae(n,t){var r,e,i,u=n.sort(ce).pop();for(ec=[],ic=new Array(n.length),uc=new re,ac=new re;;)if(i=oc,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===r&&u.y===e||(ic[u.i]=new Hr(u),Pr(u),r=u.x,e=u.y),u=n.pop();else{if(!i)break;Ir(i.arc)}t&&(Xr(t),Wr(t));var o={cells:ic,edges:ec};return uc=ac=ec=ic=null,o}function ce(n,t){return t.y-n.y||t.x-n.x}function le(n,t,r){return(n.x-r.x)*(t.y-n.y)-(n.x-t.x)*(r.y-n.y)}function fe(n){return n.x}function se(n){return n.y}function he(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pe(n,t,r,e,i,u){if(!n(t,r,e,i,u)){var o=.5*(r+i),a=.5*(e+u),c=t.nodes;c[0]&&pe(n,c[0],r,e,o,a),c[1]&&pe(n,c[1],o,e,i,a),c[2]&&pe(n,c[2],r,a,o,u),c[3]&&pe(n,c[3],o,a,i,u)}}function ve(n,t,r,e,i,u,o){var a,c=1/0;return function l(n,f,s,h,p){if(!(f>u||s>o||e>h||i>p)){if(v=n.point){var v,g=t-n.x,d=r-n.y,y=g*g+d*d;if(c>y){var m=Math.sqrt(c=y);e=t-m,i=r-m,u=t+m,o=r+m,a=v}}for(var _=n.nodes,x=.5*(f+h),M=.5*(s+p),b=t>=x,w=r>=M,k=w<<1|b,C=k+4;C>k;++k)if(n=_[3&k])switch(3&k){case 0:l(n,f,s,x,M);break;case 1:l(n,x,s,h,M);break;case 2:l(n,f,M,x,p);break;case 3:l(n,x,M,h,p)}}}(n,e,i,u,o),a}function ge(n,t){n=ao.rgb(n),t=ao.rgb(t);var r=n.r,e=n.g,i=n.b,u=t.r-r,o=t.g-e,a=t.b-i;return function(n){return"#"+Mn(Math.round(r+u*n))+Mn(Math.round(e+o*n))+Mn(Math.round(i+a*n))}}function de(n,t){var r,e={},i={};for(r in n)r in t?e[r]=_e(n[r],t[r]):i[r]=n[r];for(r in t)r in n||(i[r]=t[r]);return function(n){for(r in e)i[r]=e[r](n);return i}}function ye(n,t){return n=+n,t=+t,function(r){return n*(1-r)+t*r}}function me(n,t){var r,e,i,u=sc.lastIndex=hc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(r=sc.exec(n))&&(e=hc.exec(t));)(i=e.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(r=r[0])===(e=e[0])?a[o]?a[o]+=e:a[++o]=e:(a[++o]=null,c.push({i:o,x:ye(r,e)})),u=hc.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var r,e=0;t>e;++e)a[(r=c[e]).i]=r.x(n);return a.join("")})}function _e(n,t){for(var r,e=ao.interpolators.length;--e>=0&&!(r=ao.interpolators[e](n,t)););return r}function xe(n,t){var r,e=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(r=0;a>r;++r)e.push(_e(n[r],t[r]));for(;u>r;++r)i[r]=n[r];for(;o>r;++r)i[r]=t[r];return function(n){for(r=0;a>r;++r)i[r]=e[r](n);return i}}function Me(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function be(n){return function(t){return 1-n(1-t)}}function we(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function ke(n){return n*n}function Ce(n){return n*n*n}function Ae(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,r=t*n;return 4*(.5>n?r:3*(n-t)+r-.75)}function Se(n){return function(t){return Math.pow(t,n)}}function Ee(n){return 1-Math.cos(n*Uo)}function Ne(n){return Math.pow(2,10*(n-1))}function $e(n){return 1-Math.sqrt(1-n*n)}function je(n,t){var r;return arguments.length<2&&(t=.45),arguments.length?r=t/Io*Math.asin(1/n):(n=1,r=t/4),function(e){return 1+n*Math.pow(2,-10*e)*Math.sin((e-r)*Io/t)}}function De(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Te(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Le(n,t){n=ao.hcl(n),t=ao.hcl(t);var r=n.h,e=n.c,i=n.l,u=t.h-r,o=t.c-e,a=t.l-i;return isNaN(o)&&(o=0,e=isNaN(e)?t.c:e),isNaN(u)?(u=0,r=isNaN(r)?t.h:r):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(r+u*n,e+o*n,i+a*n)+""}}function Re(n,t){n=ao.hsl(n),t=ao.hsl(t);var r=n.h,e=n.s,i=n.l,u=t.h-r,o=t.s-e,a=t.l-i;return isNaN(o)&&(o=0,e=isNaN(e)?t.s:e),isNaN(u)?(u=0,r=isNaN(r)?t.h:r):u>180?u-=360:-180>u&&(u+=360),function(n){return ln(r+u*n,e+o*n,i+a*n)+""}}function Oe(n,t){n=ao.lab(n),t=ao.lab(t);var r=n.l,e=n.a,i=n.b,u=t.l-r,o=t.a-e,a=t.b-i;return function(n){return pn(r+u*n,e+o*n,i+a*n)+""}}function ze(n,t){return t-=n,function(r){return Math.round(n+t*r)}}function qe(n){var t=[n.a,n.b],r=[n.c,n.d],e=Pe(t),i=Ie(t,r),u=Pe(Ue(r,t,-i))||0;t[0]*r[1]<r[0]*t[1]&&(t[0]*=-1,t[1]*=-1,e*=-1,i*=-1),this.rotate=(e?Math.atan2(t[1],t[0]):Math.atan2(-r[0],r[1]))*Ho,this.translate=[n.e,n.f],this.scale=[e,u],this.skew=u?Math.atan2(i,u)*Ho:0}function Ie(n,t){return n[0]*t[0]+n[1]*t[1]}function Pe(n){var t=Math.sqrt(Ie(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ue(n,t,r){return n[0]+=r*t[0],n[1]+=r*t[1],n}function Fe(n){return n.length?n.pop()+",":""}function He(n,t,r,e){if(n[0]!==t[0]||n[1]!==t[1]){var i=r.push("translate(",null,",",null,")");e.push({i:i-4,x:ye(n[0],t[0])},{i:i-2,x:ye(n[1],t[1])})}else(t[0]||t[1])&&r.push("translate("+t+")")}function We(n,t,r,e){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),e.push({i:r.push(Fe(r)+"rotate(",null,")")-2,x:ye(n,t)})):t&&r.push(Fe(r)+"rotate("+t+")")}function Be(n,t,r,e){n!==t?e.push({i:r.push(Fe(r)+"skewX(",null,")")-2,x:ye(n,t)}):t&&r.push(Fe(r)+"skewX("+t+")")}function Ye(n,t,r,e){if(n[0]!==t[0]||n[1]!==t[1]){var i=r.push(Fe(r)+"scale(",null,",",null,")");e.push({i:i-4,x:ye(n[0],t[0])},{i:i-2,x:ye(n[1],t[1])})}else 1===t[0]&&1===t[1]||r.push(Fe(r)+"scale("+t+")")}function Ze(n,t){var r=[],e=[];return n=ao.transform(n),t=ao.transform(t),He(n.translate,t.translate,r,e),We(n.rotate,t.rotate,r,e),Be(n.skew,t.skew,r,e),Ye(n.scale,t.scale,r,e),n=t=null,function(n){for(var t,i=-1,u=e.length;++i<u;)r[(t=e[i]).i]=t.x(n);return r.join("")}}function Ve(n,t){return t=(t-=n=+n)||1/t,function(r){return(r-n)/t}}function Xe(n,t){return t=(t-=n=+n)||1/t,function(r){return Math.max(0,Math.min(1,(r-n)/t))}}function Ke(n){for(var t=n.source,r=n.target,e=Qe(t,r),i=[t];t!==e;)t=t.parent,i.push(t);for(var u=i.length;r!==e;)i.splice(u,0,r),r=r.parent;return i}function Je(n){for(var t=[],r=n.parent;null!=r;)t.push(n),n=r,r=r.parent;return t.push(n),t}function Qe(n,t){if(n===t)return n;for(var r=Je(n),e=Je(t),i=r.pop(),u=e.pop(),o=null;i===u;)o=i,i=r.pop(),u=e.pop();return o}function Ge(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ri(n){n.fixed&=-5}function ei(n,t,r){var e=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,c=-1;++c<a;)u=o[c],null!=u&&(ei(u,t,r),n.charge+=u.charge,e+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*r[n.point.index];n.charge+=n.pointCharge=l,e+=l*n.point.x,i+=l*n.point.y}n.cx=e/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var r=[n];null!=(n=r.pop());)if(t(n),(i=n.children)&&(e=i.length))for(var e,i;--e>=0;)r.push(i[e])}function oi(n,t){for(var r=[n],e=[];null!=(n=r.pop());)if(e.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)r.push(u[o]);for(;null!=(n=e.pop());)t(n)}function ai(n){return n.children}function ci(n){return n.value}function li(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,r){n.y0=t,n.y=r}function vi(n){return ao.range(n.length)}function gi(n){for(var t=-1,r=n[0].length,e=[];++t<r;)e[t]=0;return e}function di(n){for(var t,r=1,e=0,i=n[0][1],u=n.length;u>r;++r)(t=n[r][1])>i&&(e=r,i=t);return e}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function _i(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var r=-1,e=+n[0],i=(n[1]-e)/t,u=[];++r<=t;)u[r]=i*r+e;return u}function Mi(n){return[ao.min(n),ao.max(n)]}function bi(n,t){return n.value-t.value}function wi(n,t){var r=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=r,r._pack_prev=t}function ki(n,t){n._pack_next=t,t._pack_prev=n}function Ci(n,t){var r=t.x-n.x,e=t.y-n.y,i=n.r+t.r;return.999*i*i>r*r+e*e}function Ai(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((r=n.children)&&(l=r.length)){var r,e,i,u,o,a,c,l,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(r.forEach(Si),e=r[0],e.x=-e.r,e.y=0,t(e),l>1&&(i=r[1],i.x=i.r,i.y=0,t(i),l>2))for(u=r[2],$i(e,i,u),t(u),wi(e,u),e._pack_prev=u,wi(u,i),i=e._pack_next,o=3;l>o;o++){$i(e,i,u=r[o]);var v=0,g=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,g++)if(Ci(a,u)){v=1;break}if(1==v)for(c=e._pack_prev;c!==a._pack_prev&&!Ci(c,u);c=c._pack_prev,d++);v?(d>g||g==d&&i.r<e.r?ki(e,i=a):ki(e=c,i),o--):(wi(e,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,_=0;for(o=0;l>o;o++)u=r[o],u.x-=y,u.y-=m,_=Math.max(_,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=_,r.forEach(Ei)}}function Si(n){n._pack_next=n._pack_prev=n}function Ei(n){delete n._pack_next,delete n._pack_prev}function Ni(n,t,r,e){var i=n.children;if(n.x=t+=e*n.x,n.y=r+=e*n.y,n.r*=e,i)for(var u=-1,o=i.length;++u<o;)Ni(i[u],t,r,e)}function $i(n,t,r){var e=n.r+r.r,i=t.x-n.x,u=t.y-n.y;if(e&&(i||u)){var o=t.r+r.r,a=i*i+u*u;o*=o,e*=e;var c=.5+(e-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(e+a)-(e-=a)*e-o*o))/(2*a);r.x=n.x+c*i+l*u,r.y=n.y+c*u-l*i}else r.x=n.x+e,r.y=n.y}function ji(n,t){return n.parent==t.parent?1:2}function Di(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,r=n.children;return(t=r.length)?r[t-1]:n.t}function Li(n,t,r){var e=r/(t.i-n.i);t.c-=e,t.s+=r,n.c+=e,t.z+=r,t.m+=r}function Ri(n){for(var t,r=0,e=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=r,t.m+=r,r+=t.s+(e+=t.c)}function Oi(n,t,r){return n.a.parent===t.parent?n.a:r}function zi(n){return 1+ao.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ii(n){var t=n.children;return t&&t.length?Ii(t[0]):n}function Pi(n){var t,r=n.children;return r&&(t=r.length)?Pi(r[t-1]):n}function Ui(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Fi(n,t){var r=n.x+t[3],e=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(r+=i/2,i=0),0>u&&(e+=u/2,u=0),{x:r,y:e,dx:i,dy:u}}function Hi(n){var t=n[0],r=n[n.length-1];return r>t?[t,r]:[r,t]}function Wi(n){return n.rangeExtent?n.rangeExtent():Hi(n.range())}function Bi(n,t,r,e){var i=r(n[0],n[1]),u=e(t[0],t[1]);return function(n){return u(i(n))}}function Yi(n,t){var r,e=0,i=n.length-1,u=n[e],o=n[i];return u>o&&(r=e,e=i,i=r,r=u,u=o,o=r),n[e]=t.floor(u),n[i]=t.ceil(o),n}function Zi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:wc}function Vi(n,t,r,e){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(r(n[o-1],n[o])),u.push(e(t[o-1],t[o]));return function(t){var r=ao.bisect(n,t,1,a)-1;return u[r](i[r](t))}}function Xi(n,t,r,e){function i(){var i=Math.min(n.length,t.length)>2?Vi:Bi,c=e?Xe:Ve;return o=i(n,t,c,r),a=i(t,n,c,_e),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(ze)},u.clamp=function(n){return arguments.length?(e=n,i()):e},u.interpolate=function(n){return arguments.length?(r=n,i()):r},u.ticks=function(t){return Gi(n,t)},u.tickFormat=function(t,r){return nu(n,t,r)},u.nice=function(t){return Ji(n,t),i()},u.copy=function(){return Xi(n,t,r,e)},i()}function Ki(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Ji(n,t){return Yi(n,Zi(Qi(n,t)[2])),Yi(n,Zi(Qi(n,t)[2])),n}function Qi(n,t){null==t&&(t=10);var r=Hi(n),e=r[1]-r[0],i=Math.pow(10,Math.floor(Math.log(e/t)/Math.LN10)),u=t/e*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),r[0]=Math.ceil(r[0]/i)*i,r[1]=Math.floor(r[1]/i)*i+.5*i,r[2]=i,r}function Gi(n,t){return ao.range.apply(ao,Qi(n,t))}function nu(n,t,r){var e=Qi(n,t);if(r){var i=sa.exec(r);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(e[0]),xo(e[1])));return i[7]||(i[7]="."+tu(u.scale(e[2]))),i[8]="f",r=ao.format(i.join("")),function(n){return r(u.scale(n))+u.symbol}}i[7]||(i[7]="."+ru(i[8],e)),r=i.join("")}else r=",."+tu(e[2])+"f";return ao.format(r)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function ru(n,t){var r=tu(t[2]);return n in kc?Math.abs(r-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):r-2*("%"===n)}function eu(n,t,r,e){function i(n){return(r?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return r?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(r=t[0]>=0,n.domain((e=t.map(Number)).map(i)),o):e},o.base=function(r){return arguments.length?(t=+r,n.domain(e.map(i)),o):t},o.nice=function(){var t=Yi(e.map(i),r?Math:Ac);return n.domain(t),e=t.map(u),o},o.ticks=function(){var n=Hi(e),o=[],a=n[0],c=n[1],l=Math.floor(i(a)),f=Math.ceil(i(c)),s=t%1?2:t;if(isFinite(f-l)){if(r){for(;f>l;l++)for(var h=1;s>h;h++)o.push(u(l)*h);o.push(u(l))}else for(o.push(u(l));l++<f;)for(var h=s-1;h>0;h--)o.push(u(l)*h);for(l=0;o[l]<a;l++);for(f=o.length;o[f-1]>c;f--);o=o.slice(l,f)}return o},o.tickFormat=function(n,r){if(!arguments.length)return Cc;arguments.length<2?r=Cc:"function"!=typeof r&&(r=ao.format(r));var e=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),e>=o?r(n):""}},o.copy=function(){return eu(n.copy(),t,r,e)},Ki(o,n)}function iu(n,t,r){function e(t){return n(i(t))}var i=uu(t),u=uu(1/t);return e.invert=function(t){return u(n.invert(t))},e.domain=function(t){return arguments.length?(n.domain((r=t.map(Number)).map(i)),e):r},e.ticks=function(n){return Gi(r,n)},e.tickFormat=function(n,t){return nu(r,n,t)},e.nice=function(n){return e.domain(Ji(r,n))},e.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(r.map(i)),e):t},e.copy=function(){return iu(n.copy(),t,r)},Ki(e,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function r(r){return u[((i.get(r)||("range"===t.t?i.set(r,n.push(r)):NaN))-1)%u.length]}function e(t,r){return ao.range(n.length).map(function(n){return t+r*n})}var i,u,o;return r.domain=function(e){if(!arguments.length)return n;n=[],i=new l;for(var u,o=-1,a=e.length;++o<a;)i.has(u=e[o])||i.set(u,n.push(u));return r[t.t].apply(r,t.a)},r.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},r):u},r.rangePoints=function(i,a){arguments.length<2&&(a=0);var c=i[0],l=i[1],f=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return u=e(c+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},r},r.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var c=i[0],l=i[1],f=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return u=e(c+Math.round(f*a/2+(l-c-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},r},r.rangeBands=function(i,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=i[1]<i[0],f=i[l-0],s=i[1-l],h=(s-f)/(n.length-a+2*c);return u=e(f+h*c,h),l&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},r},r.rangeRoundBands=function(i,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=i[1]<i[0],f=i[l-0],s=i[1-l],h=Math.floor((s-f)/(n.length-a+2*c));return u=e(f+Math.round((s-f-(n.length-a)*h)/2),h),l&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},r},r.rangeBand=function(){return o},r.rangeExtent=function(){return Hi(t.a[0])},r.copy=function(){return ou(n,t)},r.domain(n)}function au(n,t){function u(){var r=0,e=t.length;for(a=[];++r<e;)a[r-1]=ao.quantile(n,r/e);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(e).filter(i).sort(r),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(r){return r=t.indexOf(r),0>r?[NaN,NaN]:[r>0?a[r-1]:n[0],r<a.length?a[r]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function cu(n,t,r){function e(t){return r[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=r.length/(t-n),o=r.length-1,e}var u,o;return e.domain=function(r){return arguments.length?(n=+r[0],t=+r[r.length-1],i()):[n,t]},e.range=function(n){return arguments.length?(r=n,i()):r},e.invertExtent=function(t){return t=r.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},e.copy=function(){return cu(n,t,r)},i()}function lu(n,t){function r(r){return r>=r?t[ao.bisect(n,r)]:void 0}return r.domain=function(t){return arguments.length?(n=t,r):n},r.range=function(n){return arguments.length?(t=n,r):t},r.invertExtent=function(r){return r=t.indexOf(r),[n[r-1],n[r]]},r.copy=function(){return lu(n,t)},r}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(r){return arguments.length?(n=r.map(t),t):n},t.ticks=function(t){return Gi(n,t)},t.tickFormat=function(t,r){return nu(n,t,r)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function vu(n){return n.startAngle}function gu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,r,e){return(n-r)*t-(t-e)*n>0?0:1}function mu(n,t,r,e,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?e:-e)/Math.sqrt(u*u+o*o),c=a*o,l=-a*u,f=n[0]+c,s=n[1]+l,h=t[0]+c,p=t[1]+l,v=(f+h)/2,g=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,_=r-e,x=f*p-h*s,M=(0>y?-1:1)*Math.sqrt(Math.max(0,_*_*m-x*x)),b=(x*y-d*M)/m,w=(-x*d-y*M)/m,k=(x*y+d*M)/m,C=(-x*d+y*M)/m,A=b-v,S=w-g,E=k-v,N=C-g;return A*A+S*S>E*E+N*N&&(b=k,w=C),[[b-c,w-l],[b*r/_,w*r/_]]}function _u(n){function t(t){function o(){l.push("M",u(n(f),a))}for(var c,l=[],f=[],s=-1,h=t.length,p=Sn(r),v=Sn(e);++s<h;)i.call(this,c=t[s],s)?f.push([+p.call(this,c,s),+v.call(this,c,s)]):f.length&&(o(),f=[]);return f.length&&o(),l.length?l.join(""):null}var r=Nr,e=$r,i=$t,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(e=n,t):e},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Dc.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function Mu(n){return n.join("L")+"Z"}function bu(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("H",(e[0]+(e=n[t])[0])/2,"V",e[1]);return r>1&&i.push("H",e[0]),i.join("")}function wu(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("V",(e=n[t])[1],"H",e[0]);return i.join("")}function ku(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("H",(e=n[t])[0],"V",e[1]);return i.join("")}function Cu(n,t){return n.length<4?xu(n):n[1]+Eu(n.slice(1,-1),Nu(n,t))}function Au(n,t){return n.length<3?Mu(n):n[0]+Eu((n.push(n[0]),n),Nu([n[n.length-2]].concat(n,[n[1]]),t))}function Su(n,t){return n.length<3?xu(n):n[0]+Eu(n,Nu(n,t))}function Eu(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var r=n.length!=t.length,e="",i=n[0],u=n[1],o=t[0],a=o,c=1;if(r&&(e+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],c=2),t.length>1){a=t[1],u=n[c],c++,e+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var l=2;l<t.length;l++,c++)u=n[c],a=t[l],e+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(r){var f=n[c];e+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return e}function Nu(n,t){for(var r,e=[],i=(1-t)/2,u=n[0],o=n[1],a=1,c=n.length;++a<c;)r=u,u=o,o=n[a],e.push([i*(o[0]-r[0]),i*(o[1]-r[1])]);return e}function $u(n){if(n.length<3)return xu(n);var t=1,r=n.length,e=n[0],i=e[0],u=e[1],o=[i,i,i,(e=n[1])[0]],a=[u,u,u,e[1]],c=[i,",",u,"L",Lu(Rc,o),",",Lu(Rc,a)];for(n.push(n[r-1]);++t<=r;)e=n[t],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Ru(c,o,a);return n.pop(),c.push("L",e),c.join("")}function ju(n){if(n.length<4)return xu(n);for(var t,r=[],e=-1,i=n.length,u=[0],o=[0];++e<3;)t=n[e],u.push(t[0]),o.push(t[1]);for(r.push(Lu(Rc,u)+","+Lu(Rc,o)),--e;++e<i;)t=n[e],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Ru(r,u,o);return r.join("")}function Du(n){for(var t,r,e=-1,i=n.length,u=i+4,o=[],a=[];++e<4;)r=n[e%i],o.push(r[0]),a.push(r[1]);for(t=[Lu(Rc,o),",",Lu(Rc,a)],--e;++e<u;)r=n[e%i],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Ru(t,o,a);return t.join("")}function Tu(n,t){var r=n.length-1;if(r)for(var e,i,u=n[0][0],o=n[0][1],a=n[r][0]-u,c=n[r][1]-o,l=-1;++l<=r;)e=n[l],i=l/r,e[0]=t*e[0]+(1-t)*(u+i*a),e[1]=t*e[1]+(1-t)*(o+i*c);return $u(n)}function Lu(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Ru(n,t,r){n.push("C",Lu(Tc,t),",",Lu(Tc,r),",",Lu(Lc,t),",",Lu(Lc,r),",",Lu(Rc,t),",",Lu(Rc,r))}function Ou(n,t){return(t[1]-n[1])/(t[0]-n[0])}function zu(n){for(var t=0,r=n.length-1,e=[],i=n[0],u=n[1],o=e[0]=Ou(i,u);++t<r;)e[t]=(o+(o=Ou(i=u,u=n[t+1])))/2;return e[t]=o,e}function qu(n){for(var t,r,e,i,u=[],o=zu(n),a=-1,c=n.length-1;++a<c;)t=Ou(n[a],n[a+1]),xo(t)<Oo?o[a]=o[a+1]=0:(r=o[a]/t,e=o[a+1]/t,i=r*r+e*e,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*r,o[a+1]=i*e));for(a=-1;++a<=c;)i=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Iu(n){return n.length<3?xu(n):n[0]+Eu(n,qu(n))}function Pu(n){for(var t,r,e,i=-1,u=n.length;++i<u;)t=n[i],r=t[0],e=t[1]-Uo,t[0]=r*Math.cos(e),t[1]=r*Math.sin(e);return n}function Uu(n){function t(t){function c(){g.push("M",a(n(y),s),f,l(n(d.reverse()),s),"Z")}for(var h,p,v,g=[],d=[],y=[],m=-1,_=t.length,x=Sn(r),M=Sn(i),b=r===e?function(){
+return p}:Sn(e),w=i===u?function(){return v}:Sn(u);++m<_;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),v=+M.call(this,h,m)]),y.push([+b.call(this,h,m),+w.call(this,h,m)])):d.length&&(c(),d=[],y=[]);return d.length&&c(),g.length?g.join(""):null}var r=Nr,e=Nr,i=0,u=$r,o=$t,a=xu,c=a.key,l=a,f="L",s=.7;return t.x=function(n){return arguments.length?(r=e=n,t):e},t.x0=function(n){return arguments.length?(r=n,t):r},t.x1=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=Dc.get(n)||xu).key,l=a.reverse||a,f=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Fu(n){return n.radius}function Hu(n){return[n.x,n.y]}function Wu(n){return function(){var t=n.apply(this,arguments),r=t[0],e=t[1]-Uo;return[r*Math.cos(e),r*Math.sin(e)]}}function Bu(){return 64}function Yu(){return"circle"}function Zu(n){var t=Math.sqrt(n/qo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Vu(n){return function(){var t,r,e;(t=this[n])&&(e=t[r=t.active])&&(e.timer.c=null,e.timer.t=NaN,--t.count?delete t[r]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Xu(n,t,r){return Co(n,Fc),n.namespace=t,n.id=r,n}function Ku(n,t,r,e){var i=n.id,u=n.namespace;return H(n,"function"==typeof r?function(n,o,a){n[u][i].tween.set(t,e(r.call(n,n.__data__,o,a)))}:(r=e(r),function(n){n[u][i].tween.set(t,r)}))}function Ju(n){return null==n&&(n=""),function(){this.textContent=n}}function Qu(n){return null==n?"__transition__":"__transition_"+n+"__"}function Gu(n,t,r,e,i){function u(n){var t=g.delay;return f.t=t+c,n>=t?o(n-t):void(f.c=o)}function o(r){var i=v.active,u=v[i];u&&(u.timer.c=null,u.timer.t=NaN,--v.count,delete v[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in v)if(e>+o){var l=v[o];l.timer.c=null,l.timer.t=NaN,--v.count,delete v[o]}f.c=a,Dn(function(){return f.c&&a(r||1)&&(f.c=null,f.t=NaN),1},0,c),v.active=e,g.event&&g.event.start.call(n,n.__data__,t),p=[],g.tween.forEach(function(r,e){(e=e.call(n,n.__data__,t))&&p.push(e)}),h=g.ease,s=g.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(g.event&&g.event.end.call(n,n.__data__,t),--v.count?delete v[e]:delete n[r],1):void 0}var c,f,s,h,p,v=n[r]||(n[r]={active:0,count:0}),g=v[e];g||(c=i.time,f=Dn(u,0,c),g=v[e]={tween:new l,time:c,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++v.count)}function no(n,t,r){n.attr("transform",function(n){var e=t(n);return"translate("+(isFinite(e)?e:r(n))+",0)"})}function to(n,t,r){n.attr("transform",function(n){var e=t(n);return"translate(0,"+(isFinite(e)?e:r(n))+")"})}function ro(n){return n.toISOString()}function eo(n,t,r){function e(t){return n(t)}function i(n,r){var e=n[1]-n[0],i=e/r,u=ao.bisect(Jc,i);return u==Jc.length?[t.year,Qi(n.map(function(n){return n/31536e6}),r)[2]]:u?t[i/Jc[u-1]<Jc[u]/i?u-1:u]:[nl,Qi(n,r)[2]]}return e.invert=function(t){return io(n.invert(t))},e.domain=function(t){return arguments.length?(n.domain(t),e):n.domain().map(io)},e.nice=function(n,t){function r(r){return!isNaN(r)&&!n.range(r,io(+r+1),t).length}var u=e.domain(),o=Hi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),e.domain(Yi(u,t>1?{floor:function(t){for(;r(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;r(t=n.ceil(t));)t=io(+t+1);return t}}:n))},e.ticks=function(n,t){var r=Hi(e.domain()),u=null==n?i(r,10):"number"==typeof n?i(r,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(r[0],io(+r[1]+1),1>t?1:t)},e.tickFormat=function(){return r},e.copy=function(){return eo(n.copy(),t,r)},Ki(e,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.15"},co=[].slice,lo=function(n){return co.call(n)},fo=this.document;if(fo)try{lo(fo.documentElement.childNodes)[0].nodeType}catch(so){lo=function(n){for(var t=n.length,r=new Array(t);t--;)r[t]=n[t];return r}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,vo=po.setAttribute,go=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){vo.call(this,n,t+"")},po.setAttributeNS=function(n,t,r){go.call(this,n,t,r+"")},yo.setProperty=function(n,t,r){mo.call(this,n,t+"",r)}}ao.ascending=r,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var r,e,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(e=n[i])&&e>=e){r=e;break}for(;++i<u;)null!=(e=n[i])&&r>e&&(r=e)}else{for(;++i<u;)if(null!=(e=t.call(n,n[i],i))&&e>=e){r=e;break}for(;++i<u;)null!=(e=t.call(n,n[i],i))&&r>e&&(r=e)}return r},ao.max=function(n,t){var r,e,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(e=n[i])&&e>=e){r=e;break}for(;++i<u;)null!=(e=n[i])&&e>r&&(r=e)}else{for(;++i<u;)if(null!=(e=t.call(n,n[i],i))&&e>=e){r=e;break}for(;++i<u;)null!=(e=t.call(n,n[i],i))&&e>r&&(r=e)}return r},ao.extent=function(n,t){var r,e,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(e=n[u])&&e>=e){r=i=e;break}for(;++u<o;)null!=(e=n[u])&&(r>e&&(r=e),e>i&&(i=e))}else{for(;++u<o;)if(null!=(e=t.call(n,n[u],u))&&e>=e){r=i=e;break}for(;++u<o;)null!=(e=t.call(n,n[u],u))&&(r>e&&(r=e),e>i&&(i=e))}return[r,i]},ao.sum=function(n,t){var r,e=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(r=+n[o])&&(e+=r);else for(;++o<u;)i(r=+t.call(n,n[o],o))&&(e+=r);return e},ao.mean=function(n,t){var r,u=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)i(r=e(n[a]))?u+=r:--c;else for(;++a<o;)i(r=e(t.call(n,n[a],a)))?u+=r:--c;return c?u/c:void 0},ao.quantile=function(n,t){var r=(n.length-1)*t+1,e=Math.floor(r),i=+n[e-1],u=r-e;return u?i+u*(n[e]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)i(u=e(n[c]))&&o.push(u);else for(;++c<a;)i(u=e(t.call(n,n[c],c)))&&o.push(u);return o.length?ao.quantile(o.sort(r),.5):void 0},ao.variance=function(n,t){var r,u,o=n.length,a=0,c=0,l=-1,f=0;if(1===arguments.length)for(;++l<o;)i(r=e(n[l]))&&(u=r-a,a+=u/++f,c+=u*(r-a));else for(;++l<o;)i(r=e(t.call(n,n[l],l)))&&(u=r-a,a+=u/++f,c+=u*(r-a));return f>1?c/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var _o=u(r);ao.bisectLeft=_o.left,ao.bisect=ao.bisectRight=_o.right,ao.bisector=function(n){return u(1===n.length?function(t,e){return r(n(t),e)}:n)},ao.shuffle=function(n,t,r){(u=arguments.length)<3&&(r=n.length,2>u&&(t=0));for(var e,i,u=r-t;u;)i=Math.random()*u--|0,e=n[u+t],n[u+t]=n[i+t],n[i+t]=e;return n},ao.permute=function(n,t){for(var r=t.length,e=new Array(r);r--;)e[r]=n[t[r]];return e},ao.pairs=function(n){for(var t,r=0,e=n.length-1,i=n[0],u=new Array(0>e?0:e);e>r;)u[r]=[t=i,i=n[++r]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,r=ao.min(n,o),e=new Array(r);++t<r;)for(var i,u=-1,a=e[t]=new Array(i);++u<i;)a[u]=n[u][t];return e},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var r in n)t.push(r);return t},ao.values=function(n){var t=[];for(var r in n)t.push(n[r]);return t},ao.entries=function(n){var t=[];for(var r in n)t.push({key:r,value:n[r]});return t},ao.merge=function(n){for(var t,r,e,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(r=new Array(o);--i>=0;)for(e=n[i],t=e.length;--t>=0;)r[--o]=e[t];return r};var xo=Math.abs;ao.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),(t-n)/r===1/0)throw new Error("infinite range");var e,i=[],u=a(xo(r)),o=-1;if(n*=u,t*=u,r*=u,0>r)for(;(e=n+r*++o)>t;)i.push(e/u);else for(;(e=n+r*++o)<t;)i.push(e/u);return i},ao.map=function(n,t){var r=new l;if(n instanceof l)n.forEach(function(n,t){r.set(n,t)});else if(Array.isArray(n)){var e,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)r.set(i,n[i]);else for(;++i<u;)r.set(t.call(n,e=n[i],i),e)}else for(var o in n)r.set(o,n[o]);return r};var Mo="__proto__",bo="\x00";c(l,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:v,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:g,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return e?e.call(i,o):r?o.sort(r):o;for(var c,f,s,h,p=-1,v=o.length,g=u[a++],d=new l;++p<v;)(h=d.get(c=g(f=o[p])))?h.push(f):d.set(c,[f]);return t?(f=t(),s=function(r,e){f.set(r,n(t,e,a))}):(f={},s=function(r,e){f[r]=n(t,e,a)}),d.forEach(s),f}function t(n,r){if(r>=u.length)return n;var e=[],i=o[r++];return n.forEach(function(n,i){e.push({key:n,values:t(i,r)})}),i?e.sort(function(n,t){return i(n.key,t.key)}):e}var r,e,i={},u=[],o=[];return i.map=function(t,r){return n(r,t,0)},i.entries=function(r){return t(n(ao.map,r,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return r=n,i},i.rollup=function(n){return e=n,i},i},ao.set=function(n){var t=new y;if(n)for(var r=0,e=n.length;e>r;++r)t.add(n[r]);return t},c(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:v,size:g,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var r,e=1,i=arguments.length;++e<i;)n[r=arguments[e]]=_(n,t,t[r]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new b,t=-1,r=arguments.length;++t<r;)n[arguments[t]]=w(n);return n},b.prototype.on=function(n,t){var r=n.indexOf("."),e="";if(r>=0&&(e=n.slice(r+1),n=n.slice(0,r)),n)return arguments.length<2?this[n].on(e):this[n].on(e,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(e,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(ko,"\\$&")};var ko=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,Co={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var r in t)n[r]=t[r]},Ao=function(n,t){return t.querySelector(n)},So=function(n,t){return t.querySelectorAll(n)},Eo=function(n,t){var r=n.matches||n[x(n,"matchesSelector")];return(Eo=function(n,t){return r.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ao=function(n,t){return Sizzle(n,t)[0]||null},So=Sizzle,Eo=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var No=ao.selection.prototype=[];No.select=function(n){var t,r,e,i,u=[];n=E(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(e=this[o]).parentNode;for(var c=-1,l=e.length;++c<l;)(i=e[c])?(t.push(r=n.call(i,i.__data__,c,o)),r&&"__data__"in i&&(r.__data__=i.__data__)):t.push(null)}return S(u)},No.selectAll=function(n){var t,r,e=[];n=N(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,c=o.length;++a<c;)(r=o[a])&&(e.push(t=lo(n.call(r,r.__data__,a,i))),t.parentNode=r);return S(e)};var $o={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:$o,qualify:function(n){var t=n.indexOf(":"),r=n;return t>=0&&"xmlns"!==(r=n.slice(0,t))&&(n=n.slice(t+1)),$o.hasOwnProperty(r)?{space:$o[r],local:n}:n}},No.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var r=this.node();return n=ao.ns.qualify(n),n.local?r.getAttributeNS(n.space,n.local):r.getAttribute(n)}for(t in n)this.each($(t,n[t]));return this}return this.each($(n,t))},No.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var r=this.node(),e=(n=T(n)).length,i=-1;if(t=r.classList){for(;++i<e;)if(!t.contains(n[i]))return!1}else for(t=r.getAttribute("class");++i<e;)if(!D(n[i]).test(t))return!1;return!0}for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},No.style=function(n,r,e){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(r="");for(e in n)this.each(O(e,n[e],r));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}e=""}return this.each(O(n,r,e))},No.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},No.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},No.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},No.append=function(n){return n=q(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},No.insert=function(n,t){return n=q(n),t=E(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},No.remove=function(){return this.each(I)},No.data=function(n,t){function r(n,r){var e,i,u,o=n.length,s=r.length,h=Math.min(o,s),p=new Array(s),v=new Array(s),g=new Array(o);if(t){var d,y=new l,m=new Array(o);for(e=-1;++e<o;)(i=n[e])&&(y.has(d=t.call(i,i.__data__,e))?g[e]=i:y.set(d,i),m[e]=d);for(e=-1;++e<s;)(i=y.get(d=t.call(r,u=r[e],e)))?i!==!0&&(p[e]=i,i.__data__=u):v[e]=P(u),y.set(d,!0);for(e=-1;++e<o;)e in m&&y.get(m[e])!==!0&&(g[e]=n[e])}else{for(e=-1;++e<h;)i=n[e],u=r[e],i?(i.__data__=u,p[e]=i):v[e]=P(u);for(;s>e;++e)v[e]=P(r[e]);for(;o>e;++e)g[e]=n[e]}v.update=p,v.parentNode=p.parentNode=g.parentNode=n.parentNode,a.push(v),c.push(p),f.push(g)}var e,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(e=this[0]).length);++u<o;)(i=e[u])&&(n[u]=i.__data__);return n}var a=W([]),c=S([]),f=S([]);if("function"==typeof n)for(;++u<o;)r(e=this[u],n.call(e,e.parentNode.__data__,u));else for(;++u<o;)r(e=this[u],n);return c.enter=function(){return a},c.exit=function(){return f},c},No.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},No.filter=function(n){var t,r,e,i=[];"function"!=typeof n&&(n=U(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(r=this[u]).parentNode;for(var a=0,c=r.length;c>a;a++)(e=r[a])&&n.call(e,e.__data__,a,u)&&t.push(e)}return S(i)},No.order=function(){for(var n=-1,t=this.length;++n<t;)for(var r,e=this[n],i=e.length-1,u=e[i];--i>=0;)(r=e[i])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},No.sort=function(n){n=F.apply(this,arguments);for(var t=-1,r=this.length;++t<r;)this[t].sort(n);return this.order()},No.each=function(n){return H(this,function(t,r,e){n.call(t,t.__data__,r,e)})},No.call=function(n){var t=lo(arguments);return n.apply(t[0]=this,t),this},No.empty=function(){return!this.node()},No.node=function(){for(var n=0,t=this.length;t>n;n++)for(var r=this[n],e=0,i=r.length;i>e;e++){var u=r[e];if(u)return u}return null},No.size=function(){var n=0;return H(this,function(){++n}),n};var jo=[];ao.selection.enter=W,ao.selection.enter.prototype=jo,jo.append=No.append,jo.empty=No.empty,jo.node=No.node,jo.call=No.call,jo.size=No.size,jo.select=function(n){for(var t,r,e,i,u,o=[],a=-1,c=this.length;++a<c;){e=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var l=-1,f=i.length;++l<f;)(u=i[l])?(t.push(e[l]=r=n.call(i.parentNode,u.__data__,l,a)),r.__data__=u.__data__):t.push(null)}return S(o)},jo.insert=function(n,t){return arguments.length<2&&(t=B(this)),No.insert.call(this,n,t)},ao.select=function(t){var r;return"string"==typeof t?(r=[Ao(t,fo)],r.parentNode=fo.documentElement):(r=[t],r.parentNode=n(t)),S([r])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=lo(So(n,fo)),t.parentNode=fo.documentElement):(t=lo(n),t.parentNode=null),S([t])},No.on=function(n,t,r){var e=arguments.length;if(3>e){if("string"!=typeof n){2>e&&(t=!1);for(r in n)this.each(Y(r,n[r],t));return this}if(2>e)return(e=this.node()["__on"+n])&&e._;r=!1}return this.each(Y(n,t,r))};var Do=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&Do.forEach(function(n){"on"+n in fo&&Do.remove(n)});var To,Lo=0;ao.mouse=function(n){return K(n,C())};var Ro=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,r){if(arguments.length<3&&(r=t,t=C().changedTouches),t)for(var e,i=0,u=t.length;u>i;++i)if((e=t[i]).identifier===r)return K(n,e)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function r(n,t,r,u,o){return function(){function a(){var n,r,e=t(h,g);e&&(n=e[0]-_[0],r=e[1]-_[1],v|=n|r,_=e,p({type:"drag",x:e[0]+l[0],y:e[1]+l[1],dx:n,dy:r}))}function c(){t(h,g)&&(y.on(u+d,null).on(o+d,null),m(v),p({type:"dragend"}))}var l,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=e.of(f,arguments),v=0,g=n(),d=".drag"+(null==g?"":"-"+g),y=ao.select(r(s)).on(u+d,a).on(o+d,c),m=X(s),_=t(h,g);i?(l=i.apply(f,arguments),l=[l.x-_[0],l.y-_[1]]):l=[0,0],p({type:"dragstart"})}}var e=A(n,"drag","dragstart","dragend"),i=null,u=r(M,ao.mouse,t,"mousemove","mouseup"),o=r(J,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,e,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=C().touches),t?lo(t).map(function(t){var r=K(n,t);return r.identifier=t.identifier,r}):[]};var Oo=1e-6,zo=Oo*Oo,qo=Math.PI,Io=2*qo,Po=Io-Oo,Uo=qo/2,Fo=qo/180,Ho=180/qo,Wo=Math.SQRT2,Bo=2,Yo=4;ao.interpolateZoom=function(n,t){var r,e,i=n[0],u=n[1],o=n[2],a=t[0],c=t[1],l=t[2],f=a-i,s=c-u,h=f*f+s*s;if(zo>h)e=Math.log(l/o)/Wo,r=function(n){return[i+n*f,u+n*s,o*Math.exp(Wo*n*e)]};else{var p=Math.sqrt(h),v=(l*l-o*o+Yo*h)/(2*o*Bo*p),g=(l*l-o*o-Yo*h)/(2*l*Bo*p),d=Math.log(Math.sqrt(v*v+1)-v),y=Math.log(Math.sqrt(g*g+1)-g);e=(y-d)/Wo,r=function(n){var t=n*e,r=en(d),a=o/(Bo*p)*(r*un(Wo*t+d)-rn(d));return[i+a*f,u+a*s,o*r/en(Wo*t+d)]}}return r.duration=1e3*e,r},ao.behavior.zoom=function(){function n(n){n.on(j,s).on(Vo+".zoom",p).on("dblclick.zoom",v).on(L,h)}function r(n){return[(n[0]-C.x)/C.k,(n[1]-C.y)/C.k]}function e(n){return[n[0]*C.k+C.x,n[1]*C.k+C.y]}function i(n){C.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),C.x+=n[0]-t[0],C.y+=n[1]-t[1]}function o(t,r,e,o){t.__chart__={x:C.x,y:C.y,k:C.k},i(Math.pow(2,o)),u(d=r,e),t=ao.select(t),N>0&&(t=t.transition().duration(N)),t.call(n.event)}function a(){M&&M.domain(x.range().map(function(n){return(n-C.x)/C.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-C.y)/C.k}).map(b.invert))}function c(n){$++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:C.k,translate:[C.x,C.y]})}function f(n){--$||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),l(o)}function e(){s.on(D,null).on(T,null),p(a),f(o)}var i=this,o=R.of(i,arguments),a=0,s=ao.select(t(i)).on(D,n).on(T,e),h=r(ao.mouse(i)),p=X(i);Uc.call(i),c(o)}function h(){function n(){var n=ao.touches(v);return p=C.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=r(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,e).on(M,a),b.push(t);for(var r=ao.event.changedTouches,i=0,u=r.length;u>i;++i)d[r[i].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-_){var f=c[0];o(v,f,d[f.identifier],Math.floor(Math.log(C.k)/Math.LN2)+1),k()}_=l}else if(c.length>1){var f=c[0],s=c[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function e(){var n,t,r,e,o=ao.touches(v);Uc.call(v);for(var a=0,c=o.length;c>a;++a,e=null)if(r=o[a],e=d[r.identifier]){if(t)break;n=r,t=e}if(e){var f=(f=r[0]-n[0])*f+(f=r[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+r[0])/2,(n[1]+r[1])/2],t=[(t[0]+e[0])/2,(t[1]+e[1])/2],i(s*p)}_=null,u(n,t),l(g)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,r=0,e=t.length;e>r;++r)delete d[t[r].identifier];for(var i in d)return void n()}ao.selectAll(b).on(m,null),w.on(j,s).on(L,h),A(),f(g)}var p,v=this,g=R.of(v,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,M="touchend"+m,b=[],w=ao.select(v),A=X(v);t(),c(g),w.on(j,null).on(L,t)}function p(){var n=R.of(this,arguments);m?clearTimeout(m):(Uc.call(this),g=r(d=y||ao.mouse(this)),c(n)),m=setTimeout(function(){m=null,f(n)},50),k(),i(Math.pow(2,.002*Zo())*C.k),u(d,g),l(n)}function v(){var n=ao.mouse(this),t=Math.log(C.k)/Math.LN2;o(this,n,r(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var g,d,y,m,_,x,M,b,w,C={x:0,y:0,k:1},S=[960,500],E=Xo,N=250,$=0,j="mousedown.zoom",D="mousemove.zoom",T="mouseup.zoom",L="touchstart.zoom",R=A(n,"zoomstart","zoom","zoomend");return Vo||(Vo="onwheel"in fo?(Zo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Zo=function(){return ao.event.wheelDelta},"mousewheel"):(Zo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=R.of(this,arguments),t=C;Ic?ao.select(this).transition().each("start.zoom",function(){C=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var r=S[0],e=S[1],i=d?d[0]:r/2,u=d?d[1]:e/2,o=ao.interpolateZoom([(i-C.x)/C.k,(u-C.y)/C.k,r/C.k],[(i-t.x)/t.k,(u-t.y)/t.k,r/t.k]);return function(t){var e=o(t),a=r/e[2];this.__chart__=C={x:i-e[0]*a,y:u-e[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=C,c(n),l(n),f(n))})},n.translate=function(t){return arguments.length?(C={x:+t[0],y:+t[1],k:C.k},a(),n):[C.x,C.y]},n.scale=function(t){return arguments.length?(C={x:C.x,y:C.y,k:null},i(+t),a(),n):C.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?Xo:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(S=t&&[+t[0],+t[1]],n):S},n.duration=function(t){return arguments.length?(N=+t,n):N},n.x=function(t){return arguments.length?(M=t,x=t.copy(),C={x:0,y:0,k:1},n):M},n.y=function(t){return arguments.length?(w=t,b=t.copy(),C={x:0,y:0,k:1},n):w},ao.rebind(n,R,"on")};var Zo,Vo,Xo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=cn;var Ko=cn.prototype=new an;Ko.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new cn(this.h,this.s,this.l/n)},Ko.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new cn(this.h,this.s,n*this.l)},Ko.rgb=function(){return ln(this.h,this.s,this.l)},ao.hcl=fn;var Jo=fn.prototype=new an;Jo.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Jo.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Jo.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,Go=.95047,na=1,ta=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ea=mn.prototype=new an;ea.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,r=this.g,e=this.b,i=30;return t||r||e?(t&&i>t&&(t=i),r&&i>r&&(r=i),e&&i>e&&(e=i),new mn(Math.min(255,t/n),Math.min(255,r/n),Math.min(255,e/n))):new mn(i,i,i)},ea.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ea.hsl=function(){return wn(this.r,this.g,this.b)},ea.toString=function(){return"#"+Mn(this.r)+Mn(this.g)+Mn(this.b)};var ia=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ia.forEach(function(n,t){ia.set(n,_n(t))}),ao.functor=Sn,ao.xhr=En(m),ao.dsv=function(n,t){function r(n,r,u){arguments.length<3&&(u=r,r=null);var o=Nn(n,t,null==r?e:i(r),u);return o.row=function(n){return arguments.length?o.response(null==(r=n)?e:i(n)):r},o}function e(n){return r.parse(n.responseText)}function i(n){return function(t){return r.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return r.parse=function(n,t){var e;return r.parseRows(n,function(n,r){if(e)return e(n,r-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");e=t?function(n,r){return t(i(n),r)}:i})},r.parseRows=function(n,t){function r(){if(f>=l)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var r=t;r++<l;)if(34===n.charCodeAt(r)){if(34!==n.charCodeAt(r+1))break;++r}f=r+2;var e=n.charCodeAt(r+1);return 13===e?(i=!0,10===n.charCodeAt(r+2)&&++f):10===e&&(i=!0),n.slice(t+1,r).replace(/""/g,'"')}for(;l>f;){var e=n.charCodeAt(f++),a=1;if(10===e)i=!0;else if(13===e)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(e!==c)continue;return n.slice(t,f-a)}return n.slice(t)}for(var e,i,u={},o={},a=[],l=n.length,f=0,s=0;(e=r())!==o;){for(var h=[];e!==u&&e!==o;)h.push(e),e=r();t&&null==(h=t(h,s++))||a.push(h)}return a},r.format=function(t){if(Array.isArray(t[0]))return r.formatRows(t);var e=new y,i=[];return t.forEach(function(n){for(var t in n)e.has(t)||i.push(e.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},r.formatRows=function(n){return n.map(u).join("\n")},r},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv("	","text/tab-separated-values");var ua,oa,aa,ca,la=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){Dn.apply(this,arguments)},ao.timer.flush=function(){Ln(),Rn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var fa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(zn);ao.formatPrefix=function(n,t){var r=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,On(n,t))),r=1+Math.floor(1e-12+Math.log(n)/Math.LN10),r=Math.max(-24,Math.min(24,3*Math.floor((r-1)/3)))),fa[8+r/3]};var sa=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,ha=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,On(n,t))).toFixed(Math.max(0,Math.min(20,On(n*(1+1e-15),t))))}}),pa=ao.time={},va=Date;Pn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){ga.setUTCDate.apply(this._,arguments)},setDay:function(){ga.setUTCDay.apply(this._,arguments)},setFullYear:function(){ga.setUTCFullYear.apply(this._,arguments)},setHours:function(){ga.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){ga.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){ga.setUTCMinutes.apply(this._,arguments)},setMonth:function(){ga.setUTCMonth.apply(this._,arguments)},setSeconds:function(){ga.setUTCSeconds.apply(this._,arguments)},setTime:function(){ga.setTime.apply(this._,arguments)}};var ga=Date.prototype;pa.year=Un(function(n){return n=pa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),pa.years=pa.year.range,pa.years.utc=pa.year.utc.range,pa.day=Un(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),pa.days=pa.day.range,pa.days.utc=pa.day.utc.range,pa.dayOfYear=function(n){var t=pa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var r=pa[n]=Un(function(n){return(n=pa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var r=pa.year(n).getDay();return Math.floor((pa.dayOfYear(n)+(r+t)%7)/7)-(r!==t)});pa[n+"s"]=r.range,pa[n+"s"].utc=r.utc.range,pa[n+"OfYear"]=function(n){var r=pa.year(n).getDay();return Math.floor((pa.dayOfYear(n)+(r+t)%7)/7)}}),pa.week=pa.sunday,pa.weeks=pa.sunday.range,pa.weeks.utc=pa.sunday.utc.range,pa.weekOfYear=pa.sundayOfYear;var da={"-":"",_:" ",0:"0"},ya=/^\s*\d+/,ma=/^%/;ao.locale=function(n){return{numberFormat:qn(n),timeFormat:Hn(n)}};var _a=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=_a.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,xa),st(xa.s,this.s,this),this.s?this.t+=xa.t:this.s=xa.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var xa=new ft;ao.geo.stream=function(n,t){n&&Ma.hasOwnProperty(n.type)?Ma[n.type](n,t):ht(n,t)};var Ma={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var r=n.features,e=-1,i=r.length;++e<i;)ht(r[e].geometry,t)}},ba={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)n=r[e],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)pt(r[e],t,0)},Polygon:function(n,t){vt(n.coordinates,t)},MultiPolygon:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)vt(r[e],t)},GeometryCollection:function(n,t){for(var r=n.geometries,e=-1,i=r.length;++e<i;)ht(r[e],t)}};ao.geo.area=function(n){return wa=0,ao.geo.stream(n,Ca),wa};var wa,ka=new ft,Ca={sphere:function(){wa+=4*qo},point:M,lineStart:M,lineEnd:M,polygonStart:function(){ka.reset(),Ca.lineStart=gt},polygonEnd:function(){var n=2*ka;wa+=0>n?4*qo+n:n,Ca.lineStart=Ca.lineEnd=Ca.point=M}};ao.geo.bounds=function(){function n(n,t){_.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,r){var e=dt([t*Fo,r*Fo]);if(y){var i=mt(y,e),u=[i[1],-i[0],0],o=mt(u,i);Mt(o),o=bt(o);var c=t-v,l=c>0?1:-1,g=o[0]*Ho*l,d=xo(c)>180;if(d^(g>l*v&&l*t>g)){var m=o[1]*Ho;m>p&&(p=m)}else if(g=(g+360)%360-180,d^(g>l*v&&l*t>g)){var m=-o[1]*Ho;s>m&&(s=m)}else s>r&&(s=r),r>p&&(p=r);d?v>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>v?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,r);y=e,v=t}function r(){M.point=t}function e(){x[0]=f,x[1]=h,M.point=n,y=null}function i(n,r){if(y){var e=n-v;m+=xo(e)>180?e+(e>0?360:-360):e}else g=n,d=r;Ca.point(n,r),t(n,r)}function u(){Ca.lineStart()}function o(){i(g,d),Ca.lineEnd(),xo(m)>Oo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,v,g,d,y,m,_,x,M={point:n,lineStart:r,lineEnd:e,polygonStart:function(){M.point=i,M.lineStart=u,M.lineEnd=o,m=0,Ca.polygonStart()},polygonEnd:function(){Ca.polygonEnd(),M.point=n,M.lineStart=r,M.lineEnd=e,0>ka?(f=-(h=180),s=-(p=90)):m>Oo?p=90:-Oo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),_=[],ao.geo.stream(n,M);var t=_.length;if(t){_.sort(c);for(var r,e=1,i=_[0],u=[i];t>e;++e)r=_[e],l(r[0],i)||l(r[1],i)?(a(i[0],r[1])>a(i[0],i[1])&&(i[1]=r[1]),a(r[0],i[1])>a(i[0],i[1])&&(i[0]=r[0])):u.push(i=r);for(var o,r,v=-(1/0),t=u.length-1,e=0,i=u[t];t>=e;i=r,++e)r=u[e],(o=a(i[1],r[0]))>v&&(v=o,f=r[0],h=i[1])}return _=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Aa=Sa=Ea=Na=$a=ja=Da=Ta=La=Ra=Oa=0,ao.geo.stream(n,za);var t=La,r=Ra,e=Oa,i=t*t+r*r+e*e;return zo>i&&(t=ja,r=Da,e=Ta,Oo>Sa&&(t=Ea,r=Na,e=$a),i=t*t+r*r+e*e,zo>i)?[NaN,NaN]:[Math.atan2(r,t)*Ho,tn(e/Math.sqrt(i))*Ho]};var Aa,Sa,Ea,Na,$a,ja,Da,Ta,La,Ra,Oa,za={sphere:M,point:kt,lineStart:At,lineEnd:St,polygonStart:function(){za.lineStart=Et},polygonEnd:function(){za.lineStart=At}},qa=Lt($t,qt,Pt,[-qo,-qo/2]),Ia=1e9;ao.geo.clipExtent=function(){var n,t,r,e,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Wt(n=+a[0][0],t=+a[0][1],r=+a[1][0],e=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[r,e]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Bt(Yt)}).raw=Yt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,r(u,o),t||(e(u,o),t)||i(u,o),t}var t,r,e,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,r){t=[n,r]}};return n.invert=function(n){var t=u.scale(),r=u.translate(),e=(n[0]-r[0])/t,i=(n[1]-r[1])/t;return(i>=.12&&.234>i&&e>=-.425&&-.214>e?o:i>=.166&&.234>i&&e>=-.214&&-.115>e?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),r=o.stream(n),e=a.stream(n);return{point:function(n,i){t.point(n,i),r.point(n,i),e.point(n,i)},sphere:function(){t.sphere(),r.sphere(),e.sphere()},lineStart:function(){t.lineStart(),r.lineStart(),e.lineStart()},lineEnd:function(){t.lineEnd(),r.lineEnd(),e.lineEnd()},polygonStart:function(){t.polygonStart(),r.polygonStart(),e.polygonStart()},polygonEnd:function(){t.polygonEnd(),r.polygonEnd(),e.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var l=u.scale(),f=+t[0],s=+t[1];return r=u.translate(t).clipExtent([[f-.455*l,s-.238*l],[f+.455*l,s+.238*l]]).stream(c).point,e=o.translate([f-.307*l,s+.201*l]).clipExtent([[f-.425*l+Oo,s+.12*l+Oo],[f-.214*l-Oo,s+.234*l-Oo]]).stream(c).point,i=a.translate([f-.205*l,s+.212*l]).clipExtent([[f-.214*l+Oo,s+.166*l+Oo],[f-.115*l-Oo,s+.234*l-Oo]]).stream(c).point,n},n.scale(1070)};var Pa,Ua,Fa,Ha,Wa,Ba,Ya={point:M,lineStart:M,lineEnd:M,polygonStart:function(){Ua=0,Ya.lineStart=Zt},polygonEnd:function(){Ya.lineStart=Ya.lineEnd=Ya.point=M,Pa+=xo(Ua/2)}},Za={point:Vt,lineStart:M,lineEnd:M,polygonStart:M,polygonEnd:M},Va={point:Jt,lineStart:Qt,lineEnd:Gt,polygonStart:function(){Va.lineStart=nr},polygonEnd:function(){Va.point=Jt,Va.lineStart=Qt,Va.lineEnd=Gt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var r,e,i,u,o,a=4.5;return n.area=function(n){return Pa=0,ao.geo.stream(n,i(Ya)),Pa},n.centroid=function(n){return Ea=Na=$a=ja=Da=Ta=La=Ra=Oa=0,ao.geo.stream(n,i(Va)),Oa?[La/Oa,Ra/Oa]:Ta?[ja/Ta,Da/Ta]:$a?[Ea/$a,Na/$a]:[NaN,NaN]},n.bounds=function(n){return Wa=Ba=-(Fa=Ha=1/0),ao.geo.stream(n,i(Za)),[[Fa,Ha],[Wa,Ba]]},n.projection=function(n){return arguments.length?(i=(r=n)?n.stream||er(n):m,t()):r},n.context=function(n){return arguments.length?(u=null==(e=n)?new Xt:new tr(n),"function"!=typeof a&&u.pointRadius(a),t()):e},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var r=new ir(t);for(var e in n)r[e]=n[e];return r}}},ir.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=or,ao.geo.projectionMutator=ar,(ao.geo.equirectangular=function(){return or(lr)}).raw=lr.invert=lr,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Fo,t[1]*Fo),t[0]*=Ho,t[1]*=Ho,t}return n=sr(n[0]%360*Fo,n[1]*Fo,n.length>2?n[2]*Fo:0),t.invert=function(t){return t=n.invert(t[0]*Fo,t[1]*Fo),t[0]*=Ho,t[1]*=Ho,t},t},fr.invert=lr,ao.geo.circle=function(){function n(){var n="function"==typeof e?e.apply(this,arguments):e,t=sr(-n[0]*Fo,-n[1]*Fo,0).invert,i=[];return r(null,null,1,{point:function(n,r){i.push(n=t(n,r)),n[0]*=Ho,n[1]*=Ho}}),{type:"Polygon",coordinates:[i]}}var t,r,e=[0,0],i=6;return n.origin=function(t){return arguments.length?(e=t,n):e},n.angle=function(e){return arguments.length?(r=gr((t=+e)*Fo,i*Fo),n):t},n.precision=function(e){return arguments.length?(r=gr(t*Fo,(i=+e)*Fo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var r,e=(t[0]-n[0])*Fo,i=n[1]*Fo,u=t[1]*Fo,o=Math.sin(e),a=Math.cos(e),c=Math.sin(i),l=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((r=s*o)*r+(r=l*f-c*s*a)*r),c*f+l*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(l/y)*y,c,y).map(p)).concat(ao.range(Math.ceil(e/v)*v,r,v).filter(function(n){return xo(n%d)>Oo}).map(f)).concat(ao.range(Math.ceil(a/g)*g,o,g).filter(function(n){return xo(n%y)>Oo}).map(s))}var r,e,i,u,o,a,c,l,f,s,h,p,v=10,g=v,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(c).slice(1),h(i).reverse().slice(1),p(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],l=+t[0][1],c=+t[1][1],u>i&&(t=u,u=i,i=t),l>c&&(t=l,l=c,c=t),n.precision(m)):[[u,l],[i,c]]},n.minorExtent=function(t){return arguments.length?(e=+t[0][0],r=+t[1][0],a=+t[0][1],o=+t[1][1],e>r&&(t=e,e=r,r=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[e,a],[r,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(v=+t[0],g=+t[1],n):[v,g]},n.precision=function(t){return arguments.length?(m=+t,f=yr(a,o,90),s=mr(e,r,m),h=yr(l,c,90),p=mr(u,i,m),n):m},n.majorExtent([[-180,-90+Oo],[180,90-Oo]]).minorExtent([[-180,-80-Oo],[180,80+Oo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||e.apply(this,arguments),r||i.apply(this,arguments)]}}var t,r,e=_r,i=xr;return n.distance=function(){return ao.geo.distance(t||e.apply(this,arguments),r||i.apply(this,arguments))},n.source=function(r){return arguments.length?(e=r,t="function"==typeof r?null:r,n):e},n.target=function(t){return arguments.length?(i=t,r="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return Mr(n[0]*Fo,n[1]*Fo,t[0]*Fo,t[1]*Fo)},ao.geo.length=function(n){return Xa=0,ao.geo.stream(n,Ka),Xa};var Xa,Ka={sphere:M,point:M,lineStart:br,lineEnd:M,polygonStart:M,polygonEnd:M},Ja=wr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return or(Ja)}).raw=Ja;var Qa=wr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return or(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Bt(kr)}).raw=kr,(ao.geo.conicEquidistant=function(){return Bt(Cr)}).raw=Cr;var Ga=wr(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return or(Ga)}).raw=Ga,Ar.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Uo]},(ao.geo.mercator=function(){return Sr(Ar)}).raw=Ar;var nc=wr(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return or(nc)}).raw=nc;var tc=wr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return or(tc)}).raw=tc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Uo]},(ao.geo.transverseMercator=function(){var n=Sr(Er),t=n.center,r=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?r([n[0],n[1],n.length>2?n[2]+90:90]):(n=r(),[n[0],n[1],n[2]-90])},r([0,0,90])}).raw=Er,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=Sn(r),u=Sn(e),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(Dr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=jr(a),f=jr(c),s=f[0]===l[0],h=f[f.length-1]===l[l.length-1],p=[];for(t=l.length-1;t>=0;--t)p.push(n[a[l[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var r=Nr,e=$r;return arguments.length?t(n):(t.x=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(e=n,t):e},t)},ao.geom.polygon=function(n){return Co(n,rc),n};var rc=ao.geom.polygon.prototype=[];rc.area=function(){for(var n,t=-1,r=this.length,e=this[r-1],i=0;++t<r;)n=e,e=this[t],i+=n[1]*e[0]-n[0]*e[1];return.5*i},rc.centroid=function(n){var t,r,e=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++e<i;)t=a,a=this[e],r=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*r,o+=(t[1]+a[1])*r;return[u*n,o*n]},rc.clip=function(n){for(var t,r,e,i,u,o,a=Rr(n),c=-1,l=this.length-Rr(this),f=this[l-1];++c<l;){for(t=n.slice(),n.length=0,i=this[c],u=t[(e=t.length-a)-1],r=-1;++r<e;)o=t[r],Tr(o,f,i)?(Tr(u,f,i)||n.push(Lr(u,o,f,i)),n.push(o)):Tr(u,f,i)&&n.push(Lr(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var ec,ic,uc,oc,ac,cc=[],lc=[];Hr.prototype.prepare=function(){for(var n,t=this.edges,r=t.length;r--;)n=t[r].edge,n.b&&n.a||t.splice(r,1);return t.sort(Br),t.length},te.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},re.prototype={insert:function(n,t){var r,e,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;r=n}else this._?(n=oe(this._),t.P=null,t.N=n,n.P=n.L=t,r=n):(t.P=t.N=null,this._=t,r=null);for(t.L=t.R=null,t.U=r,t.C=!0,n=t;r&&r.C;)e=r.U,r===e.L?(i=e.R,i&&i.C?(r.C=i.C=!1,e.C=!0,n=e):(n===r.R&&(ie(this,r),n=r,r=n.U),r.C=!1,e.C=!0,ue(this,e))):(i=e.L,i&&i.C?(r.C=i.C=!1,e.C=!0,n=e):(n===r.L&&(ue(this,r),n=r,r=n.U),r.C=!1,e.C=!0,ie(this,e))),r=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,r,e,i=n.U,u=n.L,o=n.R;if(r=u?o?oe(o):u:o,i?i.L===n?i.L=r:i.R=r:this._=r,u&&o?(e=r.C,r.C=n.C,r.L=u,u.U=r,r!==o?(i=r.U,r.U=n.U,n=r.R,i.L=n,r.R=o,o.U=r):(r.U=i,i=r,n=r.R)):(e=n.C,n=r),n&&(n.U=i),!e){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ie(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ue(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ie(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ue(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ie(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ue(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),e=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ae(r(n),a).cells.forEach(function(r,a){var c=r.edges,l=r.site,f=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=e&&l.x<=u&&l.y>=i&&l.y<=o?[[e,o],[u,o],[u,i],[e,i]]:[];f.point=n[a]}),t}function r(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Oo)*Oo,y:Math.round(o(n,t)/Oo)*Oo,i:t}})}var e=Nr,i=$r,u=e,o=i,a=fc;return n?t(n):(t.links=function(n){return ae(r(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ae(r(n)).cells.forEach(function(r,e){for(var i,u,o=r.site,a=r.edges.sort(Br),c=-1,l=a.length,f=a[l-1].edge,s=f.l===o?f.r:f.l;++c<l;)i=f,u=s,f=a[c].edge,s=f.l===o?f.r:f.l,e<u.i&&e<s.i&&le(o,u,s)<0&&t.push([n[e],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=Sn(e=n),t):e},t.y=function(n){return arguments.length?(o=Sn(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?fc:n,t):a===fc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===fc?null:a&&a[1]},t)};var fc=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,r,e,i){function u(n){function u(n,t,r,e,i,u,o,a){if(!isNaN(r)&&!isNaN(e))if(n.leaf){var c=n.x,f=n.y;if(null!=c)if(xo(c-r)+xo(f-e)<.01)l(n,t,r,e,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,l(n,s,c,f,i,u,o,a),l(n,t,r,e,i,u,o,a)}else n.x=r,n.y=e,n.point=t}else l(n,t,r,e,i,u,o,a)}function l(n,t,r,e,i,o,a,c){var l=.5*(i+a),f=.5*(o+c),s=r>=l,h=e>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=he()),s?i=l:a=l,h?o=f:c=f,u(n,t,r,e,i,o,a,c)}var f,s,h,p,v,g,d,y,m,_=Sn(a),x=Sn(c);if(null!=t)g=t,d=r,y=e,m=i;else if(y=m=-(g=d=1/0),s=[],h=[],v=n.length,o)for(p=0;v>p;++p)f=n[p],f.x<g&&(g=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;v>p;++p){var M=+_(f=n[p],p),b=+x(f,p);g>M&&(g=M),d>b&&(d=b),M>y&&(y=M),b>m&&(m=b),s.push(M),h.push(b)}var w=y-g,k=m-d;w>k?m=d+w:y=g+k;var C=he();if(C.add=function(n){u(C,n,+_(n,++p),+x(n,p),g,d,y,m)},C.visit=function(n){pe(n,C,g,d,y,m)},C.find=function(n){return ve(C,n[0],n[1],g,d,y,m)},p=-1,null==t){for(;++p<v;)u(C,n[p],s[p],h[p],g,d,y,m);--p}else n.forEach(C.add);return s=h=n=f=null,C}var o,a=Nr,c=$r;return(o=arguments.length)?(a=fe,c=se,3===o&&(i=r,e=t,r=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(c=n,u):c},u.extent=function(n){return arguments.length?(null==n?t=r=e=i=null:(t=+n[0][0],r=+n[0][1],e=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,r],[e,i]]},u.size=function(n){return arguments.length?(null==n?t=r=e=i=null:(t=r=0,e=+n[0],i=+n[1]),u):null==t?null:[e-t,i-r]},u)},ao.interpolateRgb=ge,ao.interpolateObject=de,ao.interpolateNumber=ye,ao.interpolateString=me;var sc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,hc=new RegExp(sc.source,"g");ao.interpolate=_e,ao.interpolators=[function(n,t){var r=typeof t;return("string"===r?ia.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?ge:me:t instanceof an?ge:Array.isArray(t)?xe:"object"===r&&isNaN(t)?de:ye)(n,t)}],ao.interpolateArray=xe;var pc=function(){return m},vc=ao.map({linear:pc,poly:Se,quad:function(){return ke},cubic:function(){return Ce},sin:function(){return Ee},exp:function(){return Ne},circle:function(){return $e},elastic:je,back:De,bounce:function(){return Te}}),gc=ao.map({"in":m,out:be,"in-out":we,"out-in":function(n){return we(be(n))}});ao.ease=function(n){var t=n.indexOf("-"),r=t>=0?n.slice(0,t):n,e=t>=0?n.slice(t+1):"in";return r=vc.get(r)||pc,e=gc.get(e)||m,Me(e(r.apply(null,co.call(arguments,1))))},ao.interpolateHcl=Le,ao.interpolateHsl=Re,ao.interpolateLab=Oe,ao.interpolateRound=ze,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var r=t.transform.baseVal.consolidate()}return new qe(r?r.matrix:dc)})(n)},qe.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var dc={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=Ze,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],r=-1,e=n.length;++r<e;)t.push(Ke(n[r]));return t}},ao.layout.chord=function(){function n(){var n,l,s,h,p,v={},g=[],d=ao.range(u),y=[];for(r=[],e=[],n=0,h=-1;++h<u;){for(l=0,p=-1;++p<u;)l+=i[h][p];g.push(l),y.push(ao.range(u)),n+=l}for(o&&d.sort(function(n,t){return o(g[n],g[t])}),a&&y.forEach(function(n,t){n.sort(function(n,r){return a(i[t][n],i[t][r])})}),n=(Io-f*u)/n,l=0,h=-1;++h<u;){for(s=l,p=-1;++p<u;){var m=d[h],_=y[m][p],x=i[m][_],M=l,b=l+=x*n;v[m+"-"+_]={index:m,subindex:_,startAngle:M,endAngle:b,value:x}}e[m]={index:m,startAngle:s,endAngle:l,value:g[m]},l+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=v[h+"-"+p],k=v[p+"-"+h];(w.value||k.value)&&r.push(w.value<k.value?{source:k,target:w}:{source:w,target:k})}c&&t()}function t(){r.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var r,e,i,u,o,a,c,l={},f=0;return l.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,r=e=null,l):i},l.padding=function(n){return arguments.length?(f=n,r=e=null,l):f},l.sortGroups=function(n){return arguments.length?(o=n,r=e=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,r=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,r&&t(),l):c},l.chords=function(){return r||n(),r},l.groups=function(){return e||n(),e},l},ao.layout.force=function(){function n(n){return function(t,r,e,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-r,c=u*u+o*o;if(c>a*a/y){if(g>c){var l=t.charge/c;n.px-=u*l,n.py-=o*l}return!0}if(t.point&&c&&g>c){var l=t.pointCharge/c;n.px-=u*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,c.resume()}var r,e,i,u,o,a,c={},l=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=yc,p=mc,v=-30,g=_c,d=.1,y=.64,_=[],x=[];return c.tick=function(){if((i*=.99)<.005)return r=null,l.end({type:"end",alpha:i=0}),!0;var t,e,c,h,p,g,y,m,M,b=_.length,w=x.length;for(e=0;w>e;++e)c=x[e],h=c.source,p=c.target,m=p.x-h.x,M=p.y-h.y,(g=m*m+M*M)&&(g=i*o[e]*((g=Math.sqrt(g))-u[e])/g,m*=g,M*=g,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=M*y,h.x+=m*(y=1-y),h.y+=M*y);if((y=i*d)&&(m=f[0]/2,M=f[1]/2,e=-1,y))for(;++e<b;)c=_[e],c.x+=(m-c.x)*y,c.y+=(M-c.y)*y;if(v)for(ei(t=ao.geom.quadtree(_),i,a),e=-1;++e<b;)(c=_[e]).fixed||t.visit(n(c));for(e=-1;++e<b;)c=_[e],c.fixed?(c.x=c.px,c.y=c.py):(c.x-=(c.px-(c.px=c.x))*s,c.y-=(c.py-(c.py=c.y))*s);l.tick({type:"tick",alpha:i})},c.nodes=function(n){return arguments.length?(_=n,c):_},c.links=function(n){return arguments.length?(x=n,c):x},c.size=function(n){return arguments.length?(f=n,c):f},c.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,c):h},c.distance=c.linkDistance,c.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,c):p},c.friction=function(n){return arguments.length?(s=+n,c):s},c.charge=function(n){return arguments.length?(v="function"==typeof n?n:+n,c):v},c.chargeDistance=function(n){return arguments.length?(g=n*n,c):Math.sqrt(g)},c.gravity=function(n){return arguments.length?(d=+n,c):d},c.theta=function(n){return arguments.length?(y=n*n,c):Math.sqrt(y)},c.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(r.c=null,r.t=NaN,r=null,l.end({type:"end",alpha:i=0})):n>0&&(l.start({type:"start",alpha:i=n}),r=Dn(c.tick)),c):i},c.start=function(){function n(n,e){if(!r){for(r=new Array(i),c=0;i>c;++c)r[c]=[];for(c=0;l>c;++c){var u=x[c];r[u.source.index].push(u.target),r[u.target.index].push(u.source)}}for(var o,a=r[t],c=-1,f=a.length;++c<f;)if(!isNaN(o=a[c][n]))return o;return Math.random()*e}var t,r,e,i=_.length,l=x.length,s=f[0],g=f[1];for(t=0;i>t;++t)(e=_[t]).index=t,e.weight=0;for(t=0;l>t;++t)e=x[t],"number"==typeof e.source&&(e.source=_[e.source]),"number"==typeof e.target&&(e.target=_[e.target]),++e.source.weight,++e.target.weight;for(t=0;i>t;++t)e=_[t],isNaN(e.x)&&(e.x=n("x",s)),isNaN(e.y)&&(e.y=n("y",g)),isNaN(e.px)&&(e.px=e.x),isNaN(e.py)&&(e.py=e.y);if(u=[],"function"==typeof h)for(t=0;l>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;l>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;l>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;l>t;++t)o[t]=p;if(a=[],"function"==typeof v)for(t=0;i>t;++t)a[t]=+v.call(this,_[t],t);else for(t=0;i>t;++t)a[t]=v;return c.resume()},c.resume=function(){return c.alpha(.1)},c.stop=function(){return c.alpha(0)},c.drag=function(){return e||(e=ao.behavior.drag().origin(m).on("dragstart.force",Ge).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ri).call(e):e},ao.rebind(c,l,"on")};var yc=20,mc=1,_c=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(l=r.call(n,u,u.depth))&&(c=l.length)){for(var c,l,f;--c>=0;)o.push(f=l[c]),f.parent=u,f.depth=u.depth+1;e&&(u.value=0),u.children=l}else e&&(u.value=+e.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var r,i;t&&(r=n.children)&&r.sort(t),e&&(i=n.parent)&&(i.value+=n.value)}),a}var t=li,r=ai,e=ci;return n.sort=function(r){return arguments.length?(t=r,n):t},n.children=function(t){return arguments.length?(r=t,n):r},n.value=function(t){return arguments.length?(e=t,n):e},n.revalue=function(t){return e&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var r;t.children||(t.value=+e.call(n,t,t.depth)||0),(r=t.parent)&&(r.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,r,e,i){var u=t.children;if(t.x=r,t.y=t.depth*i,t.dx=e,t.dy=i,u&&(o=u.length)){var o,a,c,l=-1;for(e=t.value?e/t.value:0;++l<o;)n(a=u[l],r,c=a.value*e,i),r+=c}}function t(n){var r=n.children,e=0;if(r&&(i=r.length))for(var i,u=-1;++u<i;)e=Math.max(e,t(r[u]));return 1+e}function r(r,u){var o=e.call(this,r,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var e=ao.layout.hierarchy(),i=[1,1];return r.size=function(n){return arguments.length?(i=n,r):i},ii(r,e)},ao.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(r,e){return+t.call(n,r,e)}),f=+("function"==typeof e?e.apply(this,arguments):e),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/c,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),v=ao.sum(l),g=v?(s-c*p)/v:0,d=ao.range(c),y=[];return null!=r&&d.sort(r===xc?function(n,t){return l[t]-l[n]}:function(n,t){return r(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=l[n],startAngle:f,endAngle:f+=a*g+p,padAngle:h}}),y}var t=Number,r=xc,e=0,i=Io,u=0;return n.value=function(r){return arguments.length?(t=r,n):t},n.sort=function(t){return arguments.length?(r=t,n):r},n.startAngle=function(t){return arguments.length?(e=t,n):e},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var xc={};ao.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(r,e){return t.call(n,r,e)}),f=l.map(function(t){return t.map(function(t,r){return[u.call(n,t,r),o.call(n,t,r)]})}),s=r.call(n,f,c);l=ao.permute(l,s),f=ao.permute(f,s);var h,p,v,g,d=e.call(n,f,c),y=l[0].length;for(v=0;y>v;++v)for(i.call(n,l[0][v],g=d[v],f[0][v][1]),p=1;h>p;++p)i.call(n,l[p][v],g+=f[p-1][v][1],f[p][v][1]);return a}var t=m,r=vi,e=gi,i=pi,u=si,o=hi;return n.values=function(r){return arguments.length?(t=r,n):t},n.order=function(t){return arguments.length?(r="function"==typeof t?t:Mc.get(t)||vi,n):r},n.offset=function(t){return arguments.length?(e="function"==typeof t?t:bc.get(t)||gi,n):e},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var Mc=ao.map({"inside-out":function(n){var t,r,e=n.length,i=n.map(di),u=n.map(yi),o=ao.range(e).sort(function(n,t){return i[n]-i[t]}),a=0,c=0,l=[],f=[];for(t=0;e>t;++t)r=o[t],c>a?(a+=u[r],l.push(r)):(c+=u[r],f.push(r));return f.reverse().concat(l)},reverse:function(n){return ao.range(n.length).reverse()},"default":vi}),bc=ao.map({silhouette:function(n){var t,r,e,i=n.length,u=n[0].length,o=[],a=0,c=[];for(r=0;u>r;++r){for(t=0,e=0;i>t;t++)e+=n[t][r][1];e>a&&(a=e),o.push(e)}for(r=0;u>r;++r)c[r]=(a-o[r])/2;return c},wiggle:function(n){var t,r,e,i,u,o,a,c,l,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=c=l=0,r=1;h>r;++r){for(t=0,i=0;f>t;++t)i+=n[t][r][1];for(t=0,u=0,a=s[r][0]-s[r-1][0];f>t;++t){for(e=0,o=(n[t][r][1]-n[t][r-1][1])/(2*a);t>e;++e)o+=(n[e][r][1]-n[e][r-1][1])/a;u+=o*n[t][r][1]}p[r]=c-=i?u/i*a:0,l>c&&(l=c)}for(r=0;h>r;++r)p[r]-=l;return p},expand:function(n){var t,r,e,i=n.length,u=n[0].length,o=1/i,a=[];for(r=0;u>r;++r){for(t=0,e=0;i>t;t++)e+=n[t][r][1];if(e)for(t=0;i>t;t++)n[t][r][1]/=e;else for(t=0;i>t;t++)n[t][r][1]=o}for(r=0;u>r;++r)a[r]=0;return a},zero:gi});ao.layout.histogram=function(){function n(n,u){for(var o,a,c=[],l=n.map(r,this),f=e.call(this,l,u),s=i.call(this,f,l,u),u=-1,h=l.length,p=s.length-1,v=t?1:1/h;++u<p;)o=c[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=l[u],a>=f[0]&&a<=f[1]&&(o=c[ao.bisect(s,a,1,p)-1],o.y+=v,o.push(n[u]));return c}var t=!0,r=Number,e=Mi,i=_i;return n.value=function(t){return arguments.length?(r=t,n):r},n.range=function(t){return arguments.length?(e=Sn(t),n):e},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:Sn(t),n):i},n.frequency=function(r){return arguments.length?(t=!!r,n):t},n},ao.layout.pack=function(){function n(n,u){var o=r.call(this,n,u),a=o[0],c=i[0],l=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ai),e){var s=e*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;oi(a,function(n){n.r+=s}),oi(a,Ai),oi(a,function(n){n.r-=s})}return Ni(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,r=ao.layout.hierarchy().sort(bi),e=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(r){return arguments.length?(t=null==r||"function"==typeof r?r:+r,n):t},n.padding=function(t){return arguments.length?(e=+t,n):e},ii(n,r)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,r),h.parent.m=-h.z,ui(h,e),l)ui(s,u);else{var p=s,v=s,g=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>v.x&&(v=n),n.depth>g.depth&&(g=n)});var d=a(p,v)/2-p.x,y=c[0]/(v.x+a(v,p)/2+d),m=c[1]/(g.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,r={A:null,children:[n]},e=[r];null!=(t=e.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)e.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return r.children[0]}function r(n){var t=n.children,r=n.parent.children,e=n.i?r[n.i-1]:null;if(t.length){Ri(n);var u=(t[0].z+t[t.length-1].z)/2;e?(n.z=e.z+a(n._,e._),n.m=n.z-u):n.z=u}else e&&(n.z=e.z+a(n._,e._));n.parent.A=i(n,e,n.parent.A||r[0])}function e(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,r){if(t){for(var e,i=n,u=n,o=t,c=i.parent.children[0],l=i.m,f=u.m,s=o.m,h=c.m;o=Ti(o),i=Di(i),o&&i;)c=Di(c),u=Ti(u),u.a=n,e=o.z+s-i.z-l+a(o._,i._),e>0&&(Li(Oi(o,n,r),n,e),l+=e,f+=e),s+=o.m,l+=i.m,h+=c.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!Di(c)&&(c.t=i,c.m+=l-h,r=n)}return r}function u(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=ji,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?u:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:u,n):l?c:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),c=a[0],l=0;oi(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=r(n,o):0,n.y=0,o=n)});var f=Ii(c),s=Pi(c),h=f.x-r(f,s)/2,p=s.x+r(s,f)/2;return oi(c,i?function(n){n.x=(n.x-c.x)*e[0],n.y=(c.y-n.y)*e[1]}:function(n){n.x=(n.x-h)/(p-h)*e[0],n.y=(1-(c.y?n.y/c.y:1))*e[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),r=ji,e=[1,1],i=!1;return n.separation=function(t){return arguments.length?(r=t,n):r},n.size=function(t){return arguments.length?(i=null==(e=t),n):i?null:e},n.nodeSize=function(t){return arguments.length?(i=null!=(e=t),n):i?e:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var r,e,i=-1,u=n.length;++i<u;)e=(r=n[i]).value*(0>t?0:t),r.area=isNaN(e)||0>=e?0:e}function t(r){var u=r.children;if(u&&u.length){var o,a,c,l=s(r),f=[],h=u.slice(),v=1/0,g="slice"===p?l.dx:"dice"===p?l.dy:"slice-dice"===p?1&r.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/r.value),f.area=0;(c=h.length)>0;)f.push(o=h[c-1]),f.area+=o.area,"squarify"!==p||(a=e(f,g))<=v?(h.pop(),v=a):(f.area-=f.pop().area,i(f,g,l,!1),g=Math.min(l.dx,l.dy),f.length=f.area=0,v=1/0);f.length&&(i(f,g,l,!0),f.length=f.area=0),u.forEach(t)}}function r(t){var e=t.children;if(e&&e.length){var u,o=s(t),a=e.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;u=a.pop();)c.push(u),c.area+=u.area,null!=u.z&&(i(c,u.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);e.forEach(r)}}function e(n,t){for(var r,e=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(r=n[o].area)&&(u>r&&(u=r),r>i&&(i=r));return e*=e,t*=t,e?Math.max(t*i*v/e,e/(t*u*v)):1/0}function i(n,t,r,e){var i,u=-1,o=n.length,a=r.x,l=r.y,f=t?c(n.area/t):0;
+if(t==r.dx){for((e||f>r.dy)&&(f=r.dy);++u<o;)i=n[u],i.x=a,i.y=l,i.dy=f,a+=i.dx=Math.min(r.x+r.dx-a,f?c(i.area/f):0);i.z=!0,i.dx+=r.x+r.dx-a,r.y+=f,r.dy-=f}else{for((e||f>r.dx)&&(f=r.dx);++u<o;)i=n[u],i.x=a,i.y=l,i.dx=f,l+=i.dy=Math.min(r.y+r.dy-l,f?c(i.area/f):0);i.z=!1,i.dy+=r.y+r.dy-l,r.x+=f,r.dx-=f}}function u(e){var i=o||a(e),u=i[0];return u.x=u.y=0,u.value?(u.dx=l[0],u.dy=l[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?r:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),c=Math.round,l=[1,1],f=null,s=Ui,h=!1,p="squarify",v=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(l=n,u):l},u.padding=function(n){function t(t){var r=n.call(u,t,t.depth);return null==r?Ui(t):Fi(t,"number"==typeof r?[r,r,r,r]:r)}function r(t){return Fi(t,n)}if(!arguments.length)return f;var e;return s=null==(f=n)?Ui:"function"==(e=typeof n)?t:"number"===e?(n=[n,n,n,n],r):r,u},u.round=function(n){return arguments.length?(c=n?Math.round:Number,u):c!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(v=n,u):v},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var r=arguments.length;return 2>r&&(t=1),1>r&&(n=0),function(){var r,e,i;do r=2*Math.random()-1,e=2*Math.random()-1,i=r*r+e*e;while(!i||i>1);return n+t*r*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,r=0;n>r;r++)t+=Math.random();return t}}},ao.scale={};var wc={floor:m,ceil:m};ao.scale.linear=function(){return Xi([0,1],[0,1],_e,!1)};var kc={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return eu(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Cc=ao.format(".0e"),Ac={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Sc)},ao.scale.category20=function(){return ao.scale.ordinal().range(Ec)},ao.scale.category20b=function(){return ao.scale.ordinal().range(Nc)},ao.scale.category20c=function(){return ao.scale.ordinal().range($c)};var Sc=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Ec=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),Nc=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),$c=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return cu(0,1,[0,1])},ao.scale.threshold=function(){return lu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+r.apply(this,arguments)),l=Math.max(0,+e.apply(this,arguments)),f=o.apply(this,arguments)-Uo,s=a.apply(this,arguments)-Uo,h=Math.abs(s-f),p=f>s?0:1;if(n>l&&(v=l,l=n,n=v),h>=Po)return t(l,p)+(n?t(n,1-p):"")+"Z";var v,g,d,y,m,_,x,M,b,w,k,C,A=0,S=0,E=[];if((y=(+c.apply(this,arguments)||0)/2)&&(d=u===jc?Math.sqrt(n*n+l*l):+u.apply(this,arguments),p||(S*=-1),l&&(S=tn(d/l*Math.sin(y))),n&&(A=tn(d/n*Math.sin(y)))),l){m=l*Math.cos(f+S),_=l*Math.sin(f+S),x=l*Math.cos(s-S),M=l*Math.sin(s-S);var N=Math.abs(s-f-2*S)<=qo?0:1;if(S&&yu(m,_,x,M)===p^N){var $=(f+s)/2;m=l*Math.cos($),_=l*Math.sin($),x=M=null}}else m=_=0;if(n){b=n*Math.cos(s-A),w=n*Math.sin(s-A),k=n*Math.cos(f+A),C=n*Math.sin(f+A);var j=Math.abs(f-s+2*A)<=qo?0:1;if(A&&yu(b,w,k,C)===1-p^j){var D=(f+s)/2;b=n*Math.cos(D),w=n*Math.sin(D),k=C=null}}else b=w=0;if(h>Oo&&(v=Math.min(Math.abs(l-n)/2,+i.apply(this,arguments)))>.001){g=l>n^p?0:1;var T=v,L=v;if(qo>h){var R=null==k?[b,w]:null==x?[m,_]:Lr([m,_],[k,C],[x,M],[b,w]),O=m-R[0],z=_-R[1],q=x-R[0],I=M-R[1],P=1/Math.sin(Math.acos((O*q+z*I)/(Math.sqrt(O*O+z*z)*Math.sqrt(q*q+I*I)))/2),U=Math.sqrt(R[0]*R[0]+R[1]*R[1]);L=Math.min(v,(n-U)/(P-1)),T=Math.min(v,(l-U)/(P+1))}if(null!=x){var F=mu(null==k?[b,w]:[k,C],[m,_],l,T,p),H=mu([x,M],[b,w],l,T,p);v===T?E.push("M",F[0],"A",T,",",T," 0 0,",g," ",F[1],"A",l,",",l," 0 ",1-p^yu(F[1][0],F[1][1],H[1][0],H[1][1]),",",p," ",H[1],"A",T,",",T," 0 0,",g," ",H[0]):E.push("M",F[0],"A",T,",",T," 0 1,",g," ",H[0])}else E.push("M",m,",",_);if(null!=k){var W=mu([m,_],[k,C],n,-L,p),B=mu([b,w],null==x?[m,_]:[x,M],n,-L,p);v===L?E.push("L",B[0],"A",L,",",L," 0 0,",g," ",B[1],"A",n,",",n," 0 ",p^yu(B[1][0],B[1][1],W[1][0],W[1][1]),",",1-p," ",W[1],"A",L,",",L," 0 0,",g," ",W[0]):E.push("L",B[0],"A",L,",",L," 0 0,",g," ",W[0])}else E.push("L",b,",",w)}else E.push("M",m,",",_),null!=x&&E.push("A",l,",",l," 0 ",N,",",p," ",x,",",M),E.push("L",b,",",w),null!=k&&E.push("A",n,",",n," 0 ",j,",",1-p," ",k,",",C);return E.push("Z"),E.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var r=hu,e=pu,i=su,u=jc,o=vu,a=gu,c=du;return n.innerRadius=function(t){return arguments.length?(r=Sn(t),n):r},n.outerRadius=function(t){return arguments.length?(e=Sn(t),n):e},n.cornerRadius=function(t){return arguments.length?(i=Sn(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==jc?jc:Sn(t),n):u},n.startAngle=function(t){return arguments.length?(o=Sn(t),n):o},n.endAngle=function(t){return arguments.length?(a=Sn(t),n):a},n.padAngle=function(t){return arguments.length?(c=Sn(t),n):c},n.centroid=function(){var n=(+r.apply(this,arguments)+ +e.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Uo;return[Math.cos(t)*n,Math.sin(t)*n]},n};var jc="auto";ao.svg.line=function(){return _u(m)};var Dc=ao.map({linear:xu,"linear-closed":Mu,step:bu,"step-before":wu,"step-after":ku,basis:$u,"basis-open":ju,"basis-closed":Du,bundle:Tu,cardinal:Su,"cardinal-open":Cu,"cardinal-closed":Au,monotone:Iu});Dc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Tc=[0,2/3,1/3,0],Lc=[0,1/3,2/3,0],Rc=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=_u(Pu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=ku,ku.reverse=wu,ao.svg.area=function(){return Uu(m)},ao.svg.area.radial=function(){var n=Uu(Pu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var c=t(this,u,n,a),l=t(this,o,n,a);return"M"+c.p0+e(c.r,c.p1,c.a1-c.a0)+(r(c,l)?i(c.r,c.p1,c.r,c.p0):i(c.r,c.p1,l.r,l.p0)+e(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,r,e){var i=t.call(n,r,e),u=a.call(n,i,e),o=c.call(n,i,e)-Uo,f=l.call(n,i,e)-Uo;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function r(n,t){return n.a0==t.a0&&n.a1==t.a1}function e(n,t,r){return"A"+n+","+n+" 0 "+ +(r>qo)+",1 "+t}function i(n,t,r,e){return"Q 0,0 "+e}var u=_r,o=xr,a=Fu,c=vu,l=gu;return n.radius=function(t){return arguments.length?(a=Sn(t),n):a},n.source=function(t){return arguments.length?(u=Sn(t),n):u},n.target=function(t){return arguments.length?(o=Sn(t),n):o},n.startAngle=function(t){return arguments.length?(c=Sn(t),n):c},n.endAngle=function(t){return arguments.length?(l=Sn(t),n):l},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=r.call(this,n,i),a=(u.y+o.y)/2,c=[u,{x:u.x,y:a},{x:o.x,y:a},o];return c=c.map(e),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=_r,r=xr,e=Hu;return n.source=function(r){return arguments.length?(t=Sn(r),n):t},n.target=function(t){return arguments.length?(r=Sn(t),n):r},n.projection=function(t){return arguments.length?(e=t,n):e},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Hu,r=n.projection;return n.projection=function(n){return arguments.length?r(Wu(t=n)):t},n},ao.svg.symbol=function(){function n(n,e){return(Oc.get(t.call(this,n,e))||Zu)(r.call(this,n,e))}var t=Yu,r=Bu;return n.type=function(r){return arguments.length?(t=Sn(r),n):t},n.size=function(t){return arguments.length?(r=Sn(t),n):r},n};var Oc=ao.map({circle:Zu,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*qc)),r=t*qc;return"M0,"+-t+"L"+r+",0 0,"+t+" "+-r+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/zc),r=t*zc/2;return"M0,"+r+"L"+t+","+-r+" "+-t+","+-r+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/zc),r=t*zc/2;return"M0,"+-r+"L"+t+","+r+" "+-t+","+r+"Z"}});ao.svg.symbolTypes=Oc.keys();var zc=Math.sqrt(3),qc=Math.tan(30*Fo);No.transition=function(n){for(var t,r,e=Ic||++Hc,i=Qu(n),u=[],o=Pc||{time:Date.now(),ease:Ae,delay:0,duration:250},a=-1,c=this.length;++a<c;){u.push(t=[]);for(var l=this[a],f=-1,s=l.length;++f<s;)(r=l[f])&&Gu(r,f,i,e,o),t.push(r)}return Xu(u,i,e)},No.interrupt=function(n){return this.each(null==n?Uc:Vu(Qu(n)))};var Ic,Pc,Uc=Vu(Qu()),Fc=[],Hc=0;Fc.call=No.call,Fc.empty=No.empty,Fc.node=No.node,Fc.size=No.size,ao.transition=function(n,t){return n&&n.transition?Ic?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Fc,Fc.select=function(n){var t,r,e,i=this.id,u=this.namespace,o=[];n=E(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],f=-1,s=l.length;++f<s;)(e=l[f])&&(r=n.call(e,e.__data__,f,a))?("__data__"in e&&(r.__data__=e.__data__),Gu(r,f,u,i,e[u][i]),t.push(r)):t.push(null)}return Xu(o,u,i)},Fc.selectAll=function(n){var t,r,e,i,u,o=this.id,a=this.namespace,c=[];n=N(n);for(var l=-1,f=this.length;++l<f;)for(var s=this[l],h=-1,p=s.length;++h<p;)if(e=s[h]){u=e[a][o],r=n.call(e,e.__data__,h,l),c.push(t=[]);for(var v=-1,g=r.length;++v<g;)(i=r[v])&&Gu(i,v,a,o,u),t.push(i)}return Xu(c,a,o)},Fc.filter=function(n){var t,r,e,i=[];"function"!=typeof n&&(n=U(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var r=this[u],a=0,c=r.length;c>a;a++)(e=r[a])&&n.call(e,e.__data__,a,u)&&t.push(e)}return Xu(i,this.namespace,this.id)},Fc.tween=function(n,t){var r=this.id,e=this.namespace;return arguments.length<2?this.node()[e][r].tween.get(n):H(this,null==t?function(t){t[e][r].tween.remove(n)}:function(i){i[e][r].tween.set(n,t)})},Fc.attr=function(n,t){function r(){this.removeAttribute(a)}function e(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?r:(n+="",function(){var t,r=this.getAttribute(a);return r!==n&&(t=o(r,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?e:(n+="",function(){var t,r=this.getAttributeNS(a.space,a.local);return r!==n&&(t=o(r,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Ze:_e,a=ao.ns.qualify(n);return Ku(this,"attr."+n,t,a.local?u:i)},Fc.attrTween=function(n,t){function r(n,r){var e=t.call(this,n,r,this.getAttribute(i));return e&&function(n){this.setAttribute(i,e(n))}}function e(n,r){var e=t.call(this,n,r,this.getAttributeNS(i.space,i.local));return e&&function(n){this.setAttributeNS(i.space,i.local,e(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?e:r)},Fc.style=function(n,r,e){function i(){this.style.removeProperty(n)}function u(r){return null==r?i:(r+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==r&&(i=_e(u,r),function(t){this.style.setProperty(n,i(t),e)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(r="");for(e in n)this.style(e,n[e],r);return this}e=""}return Ku(this,"style."+n,r,u)},Fc.styleTween=function(n,r,e){function i(i,u){var o=r.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,i)},Fc.text=function(n){return Ku(this,"text",n,Ju)},Fc.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Fc.ease=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),H(this,function(e){e[r][t].ease=n}))},Fc.delay=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].delay:H(this,"function"==typeof n?function(e,i,u){e[r][t].delay=+n.call(e,e.__data__,i,u)}:(n=+n,function(e){e[r][t].delay=n}))},Fc.duration=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].duration:H(this,"function"==typeof n?function(e,i,u){e[r][t].duration=Math.max(1,n.call(e,e.__data__,i,u))}:(n=Math.max(1,n),function(e){e[r][t].duration=n}))},Fc.each=function(n,t){var r=this.id,e=this.namespace;if(arguments.length<2){var i=Pc,u=Ic;try{Ic=r,H(this,function(t,i,u){Pc=t[e][r],n.call(t,t.__data__,i,u)})}finally{Pc=i,Ic=u}}else H(this,function(i){var u=i[e][r];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Fc.transition=function(){for(var n,t,r,e,i=this.id,u=++Hc,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],f=0,s=t.length;s>f;f++)(r=t[f])&&(e=r[o][i],Gu(r,f,o,u,{time:e.time,ease:e.ease,delay:e.delay+e.duration,duration:e.duration})),n.push(r)}return Xu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,l=ao.select(this),f=this.__chart__||r,s=this.__chart__=r.copy(),h=null==c?s.ticks?s.ticks.apply(s,a):s.domain():c,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,v=l.selectAll(".tick").data(h,s),g=v.enter().insert("g",".domain").attr("class","tick").style("opacity",Oo),d=ao.transition(v.exit()).style("opacity",Oo).remove(),y=ao.transition(v.order()).style("opacity",1),_=Math.max(i,0)+o,x=Wi(s),M=l.selectAll(".domain").data([0]),b=(M.enter().append("path").attr("class","domain"),ao.transition(M));g.append("line"),g.append("text");var w,k,C,A,S=g.select("line"),E=y.select("line"),N=v.select("text").text(p),$=g.select("text"),j=y.select("text"),D="top"===e||"left"===e?-1:1;if("bottom"===e||"top"===e?(n=no,w="x",C="y",k="x2",A="y2",N.attr("dy",0>D?"0em":".71em").style("text-anchor","middle"),b.attr("d","M"+x[0]+","+D*u+"V0H"+x[1]+"V"+D*u)):(n=to,w="y",C="x",k="y2",A="x2",N.attr("dy",".32em").style("text-anchor",0>D?"end":"start"),b.attr("d","M"+D*u+","+x[0]+"H0V"+x[1]+"H"+D*u)),S.attr(A,D*i),$.attr(C,D*_),E.attr(k,0).attr(A,D*i),j.attr(w,0).attr(C,D*_),s.rangeBand){var T=s,L=T.rangeBand()/2;f=s=function(n){return T(n)+L}}else f.rangeBand?f=s:d.call(n,s,f);g.call(n,f,s),y.call(n,s,s)})}var t,r=ao.scale.linear(),e=Wc,i=6,u=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(r=t,n):r},n.orient=function(t){return arguments.length?(e=t in Bc?t+"":Wc,n):e},n.ticks=function(){return arguments.length?(a=lo(arguments),n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(r){return arguments.length?(t=r,n):t},n.tickSize=function(t){var r=arguments.length;return r?(i=+t,u=+arguments[r-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Wc="bottom",Bc={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(g,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Yc[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,s=ao.transition(t),h=ao.transition(o);l&&(c=Wi(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),e(s)),f&&(c=Wi(f),h.attr("y",c[0]).attr("height",c[1]-c[0]),i(s)),r(s)})}function r(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(N||(_=null,j[0]-=s[1],j[1]-=h[1],N=2),k())}function g(){32==ao.event.keyCode&&2==N&&(j[0]+=s[1],j[1]+=h[1],N=0,k())}function d(){var n=ao.mouse(M),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),N||(ao.event.altKey?(_||(_=[(s[0]+s[1])/2,(h[0]+h[1])/2]),j[0]=s[+(n[0]<_[0])],j[1]=h[+(n[1]<_[1])]):_=null),S&&y(n,l,0)&&(e(C),t=!0),E&&y(n,f,1)&&(i(C),t=!0),t&&(r(C),w({type:"brush",mode:N?"move":"resize"}))}function y(n,t,r){var e,i,u=Wi(t),c=u[0],l=u[1],f=j[r],g=r?h:s,d=g[1]-g[0];return N&&(c-=f,l-=d+f),e=(r?v:p)?Math.max(c,Math.min(l,n[r])):n[r],N?i=(e+=f)+d:(_&&(f=Math.max(c,Math.min(l,2*_[r]-e))),e>f?(i=e,e=f):i=f),g[0]!=e||g[1]!=i?(r?a=null:o=null,g[0]=e,g[1]=i,!0):void 0}function m(){d(),C.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),D.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),$(),w({type:"brushend"})}var _,x,M=this,b=ao.select(ao.event.target),w=c.of(M,arguments),C=ao.select(M),A=b.datum(),S=!/^(n|s)$/.test(A)&&l,E=!/^(e|w)$/.test(A)&&f,N=b.classed("extent"),$=X(M),j=ao.mouse(M),D=ao.select(t(M)).on("keydown.brush",u).on("keyup.brush",g);if(ao.event.changedTouches?D.on("touchmove.brush",d).on("touchend.brush",m):D.on("mousemove.brush",d).on("mouseup.brush",m),C.interrupt().selectAll("*").interrupt(),N)j[0]=s[0]-j[0],j[1]=h[0]-j[1];else if(A){var T=+/w$/.test(A),L=+/^n/.test(A);x=[s[1-T]-j[0],h[1-L]-j[1]],j[0]=s[T],j[1]=h[L]}else ao.event.altKey&&(_=j.slice());C.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=A(n,"brushstart","brush","brushend"),l=null,f=null,s=[0,0],h=[0,0],p=!0,v=!0,g=Zc[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:s,y:h,i:o,j:a},r=this.__chart__||t;this.__chart__=t,Ic?ao.select(this).transition().each("start.brush",function(){o=r.i,a=r.j,s=r.x,h=r.y,n({type:"brushstart"})}).tween("brush:brush",function(){var r=xe(s,t.x),e=xe(h,t.y);return o=a=null,function(i){s=t.x=r(i),h=t.y=e(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,g=Zc[!l<<1|!f],n):l},n.y=function(t){return arguments.length?(f=t,g=Zc[!l<<1|!f],n):f},n.clamp=function(t){return arguments.length?(l&&f?(p=!!t[0],v=!!t[1]):l?p=!!t:f&&(v=!!t),n):l&&f?[p,v]:l?p:f?v:null},n.extent=function(t){var r,e,i,u,c;return arguments.length?(l&&(r=t[0],e=t[1],f&&(r=r[0],e=e[0]),o=[r,e],l.invert&&(r=l(r),e=l(e)),r>e&&(c=r,r=e,e=c),r==s[0]&&e==s[1]||(s=[r,e])),f&&(i=t[0],u=t[1],l&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(c=i,i=u,u=c),i==h[0]&&u==h[1]||(h=[i,u])),n):(l&&(o?(r=o[0],e=o[1]):(r=s[0],e=s[1],l.invert&&(r=l.invert(r),e=l.invert(e)),r>e&&(c=r,r=e,e=c))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(c=i,i=u,u=c))),l&&f?[[r,i],[e,u]]:l?[r,e]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,c,"on")};var Yc={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Zc=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Vc=pa.format=_a.timeFormat,Xc=Vc.utc,Kc=Xc("%Y-%m-%dT%H:%M:%S.%LZ");Vc.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ro:Kc,ro.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},ro.toString=Kc.toString,pa.second=Un(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),pa.seconds=pa.second.range,pa.seconds.utc=pa.second.utc.range,pa.minute=Un(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),pa.minutes=pa.minute.range,pa.minutes.utc=pa.minute.utc.range,pa.hour=Un(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),pa.hours=pa.hour.range,pa.hours.utc=pa.hour.utc.range,pa.month=Un(function(n){return n=pa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),pa.months=pa.month.range,pa.months.utc=pa.month.utc.range;var Jc=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Qc=[[pa.second,1],[pa.second,5],[pa.second,15],[pa.second,30],[pa.minute,1],[pa.minute,5],[pa.minute,15],[pa.minute,30],[pa.hour,1],[pa.hour,3],[pa.hour,6],[pa.hour,12],[pa.day,1],[pa.day,2],[pa.week,1],[pa.month,1],[pa.month,3],[pa.year,1]],Gc=Vc.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",$t]]),nl={range:function(n,t,r){return ao.range(Math.ceil(n/r)*r,+t,r).map(io)},floor:m,ceil:m};Qc.year=pa.year,pa.scale=function(){return eo(ao.scale.linear(),Qc,Gc)};var tl=Qc.map(function(n){return[n[0].utc,n[1]]}),rl=Xc.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",$t]]);tl.year=pa.year.utc,pa.scale.utc=function(){return eo(ao.scale.linear(),tl,rl)},ao.text=En(function(n){return n.responseText}),ao.json=function(n,t){return Nn(n,"application/json",uo,t)},ao.html=function(n,t){return Nn(n,"text/html",oo,t)},ao.xml=En(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}(),function(){function n(n,t){return n.set(t[0],t[1]),n}function t(n,t){return n.add(t),n}function r(n,t,r){var e=r?r.length:0;switch(e){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function e(n,t){for(var r=-1,e=n.length,i=-1,u=t.length,o=Array(e+u);++r<e;)o[r]=n[r];for(;++i<u;)o[r++]=t[i];return o}function i(n,t){for(var r=-1,e=n.length;++r<e&&t(n[r],r,n)!==!1;);return n}function u(n,t){for(var r=n.length;r--&&t(n[r],r,n)!==!1;);return n}function o(n,t){for(var r=-1,e=n.length;++r<e;)if(!t(n[r],r,n))return!1;return!0}function a(n,t){for(var r=-1,e=n.length,i=-1,u=[];++r<e;){var o=n[r];t(o,r,n)&&(u[++i]=o)}return u}function c(n,t){return!!n.length&&m(n,t,0)>-1}function l(n,t,r){for(var e=-1,i=n.length;++e<i;)if(r(t,n[e]))return!0;return!1}function f(n,t){for(var r=-1,e=n.length,i=Array(e);++r<e;)i[r]=t(n[r],r,n);return i}function s(n,t){for(var r=-1,e=t.length,i=n.length;++r<e;)n[i+r]=t[r];return n}function h(n,t,r,e){var i=-1,u=n.length;for(e&&u&&(r=n[++i]);++i<u;)r=t(r,n[i],i,n);return r}function p(n,t,r,e){var i=n.length;for(e&&i&&(r=n[--i]);i--;)r=t(r,n[i],i,n);return r}function v(n,t){for(var r=-1,e=n.length;++r<e;)if(t(n[r],r,n))return!0;return!1}function g(n,t,r){for(var e=-1,i=n.length;++e<i;){var u=n[e],o=t(u);if(null!=o&&(a===B?o===o:r(o,a)))var a=o,c=u}return c}function d(n,t,r,e){var i;return r(n,function(n,r,u){return t(n,r,u)?(i=e?r:n,!1):void 0}),i}function y(n,t,r){for(var e=n.length,i=r?e:-1;r?i--:++i<e;)if(t(n[i],i,n))return i;return-1}function m(n,t,r){if(t!==t)return L(n,r);for(var e=r-1,i=n.length;++e<i;)if(n[e]===t)return e;return-1}function _(n,t,r,e,i){return i(n,function(n,i,u){r=e?(e=!1,n):t(r,n,i,u)}),r}function x(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].value;return n}function M(n,t){for(var r,e=-1,i=n.length;++e<i;){var u=t(n[e]);u!==B&&(r=r===B?u:r+u)}return r}function b(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function w(n,t){return f(t,function(t){return[t,n[t]]})}function k(n){return function(t){return n(t)}}function C(n,t){return f(t,function(t){return n[t]})}function A(n,t){for(var r=-1,e=n.length;++r<e&&m(t,n[r],0)>-1;);return r}function S(n,t){for(var r=n.length;r--&&m(t,n[r],0)>-1;);return r}function E(n){return n&&n.Object===Object?n:null}function N(n,t){if(n!==t){var r=null===n,e=n===B,i=n===n,u=null===t,o=t===B,a=t===t;if(n>t&&!u||!i||r&&!o&&a||e&&a)return 1;if(t>n&&!r||!a||u&&!e&&i||o&&i)return-1}return 0}function $(n,t,r){for(var e=-1,i=n.criteria,u=t.criteria,o=i.length,a=r.length;++e<o;){var c=N(i[e],u[e]);if(c){if(e>=a)return c;var l=r[e];return c*("desc"==l?-1:1)}}return n.index-t.index}function j(n){return gr[n]}function D(n){return dr[n]}function T(n){return"\\"+_r[n]}function L(n,t,r){for(var e=n.length,i=t+(r?0:-1);r?i--:++i<e;){var u=n[i];if(u!==u)return i}return-1}function R(n){var t=!1;if(null!=n&&"function"!=typeof n.toString)try{t=!!(n+"")}catch(r){}return t}function O(n,t){return n="number"==typeof n||Mt.test(n)?+n:-1,t=null==t?yn:t,n>-1&&n%1==0&&t>n}function z(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}function q(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function I(n,t){for(var r=-1,e=n.length,i=-1,u=[];++r<e;)n[r]===t&&(n[r]=wn,u[++i]=r);return u}function P(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function U(n){if(!n||!ar.test(n))return n.length;for(var t=or.lastIndex=0;or.test(n);)t++;return t}function F(n){return n.match(or)}function H(n){return yr[n]}function W(E){function qn(n){if(wo(n)&&!nf(n)&&!(n instanceof At)){if(n instanceof Ct)return n;if(Cc.call(n,"__wrapped__"))return Mi(n)}return new Ct(n)}function Mt(){}function Ct(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=B}function At(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=xn,this.__views__=[]}function St(){var n=new At(this.__wrapped__);return n.__actions__=Ae(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ae(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ae(this.__views__),n}function Et(){if(this.__filtered__){var n=new At(this);n.__dir__=-1,n.__filtered__=!0}else n=this.clone(),n.__dir__*=-1;return n}function Nt(){var n=this.__wrapped__.value(),t=this.__dir__,r=nf(n),e=0>t,i=r?n.length:0,u=ri(0,i,this.__views__),o=u.start,a=u.end,c=a-o,l=e?a:o-1,f=this.__iteratees__,s=f.length,h=0,p=Vc(c,this.__takeCount__);if(!r||fn>i||i==c&&p==c)return de(n,this.__actions__);var v=[];n:for(;c--&&p>h;){l+=t;for(var g=-1,d=n[l];++g<s;){var y=f[g],m=y.iteratee,_=y.type,x=m(d);if(_==hn)d=x;else if(!x){if(_==sn)continue n;break n}}v[h++]=d}return v}function $t(){}function jt(n,t){return Tt(n,t)&&delete n[t]}function Dt(n,t){if(tl){var r=n[t];return r===gn?B:r}return Cc.call(n,t)?n[t]:B}function Tt(n,t){return tl?n[t]!==B:Cc.call(n,t)}function Lt(n,t,r){n[t]=tl&&r===B?gn:r}function Rt(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Ot(){this.__data__={hash:new $t,map:Qc?new Qc:[],string:new $t}}function zt(n){var t=this.__data__;return fi(n)?jt("string"==typeof n?t.string:t.hash,n):Qc?t.map["delete"](n):Kt(t.map,n)}function qt(n){var t=this.__data__;return fi(n)?Dt("string"==typeof n?t.string:t.hash,n):Qc?t.map.get(n):Jt(t.map,n)}function It(n){var t=this.__data__;return fi(n)?Tt("string"==typeof n?t.string:t.hash,n):Qc?t.map.has(n):Qt(t.map,n)}function Pt(n,t){var r=this.__data__;return fi(n)?Lt("string"==typeof n?r.string:r.hash,n,t):Qc?r.map.set(n,t):nr(r.map,n,t),this}function Ut(n){var t=-1,r=n?n.length:0;for(this.__data__=new Rt;++t<r;)this.push(n[t])}function Ft(n,t){var r=n.__data__;if(fi(t)){var e=r.__data__,i="string"==typeof t?e.string:e.hash;return i[t]===gn}return r.has(t)}function Ht(n){var t=this.__data__;if(fi(n)){var r=t.__data__,e="string"==typeof n?r.string:r.hash;e[n]=gn}else t.set(n,gn)}function Wt(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Bt(){this.__data__={array:[],map:null}}function Yt(n){var t=this.__data__,r=t.array;return r?Kt(r,n):t.map["delete"](n)}function Zt(n){var t=this.__data__,r=t.array;return r?Jt(r,n):t.map.get(n)}function Vt(n){var t=this.__data__,r=t.array;return r?Qt(r,n):t.map.has(n)}function Xt(n,t){var r=this.__data__,e=r.array;e&&(e.length<fn-1?nr(e,n,t):(r.array=null,r.map=new Rt(e)));var i=r.map;return i&&i.set(n,t),this}function Kt(n,t){var r=Gt(n,t);if(0>r)return!1;var e=n.length-1;return r==e?n.pop():Uc.call(n,r,1),!0}function Jt(n,t){var r=Gt(n,t);return 0>r?B:n[r][1]}function Qt(n,t){return Gt(n,t)>-1}function Gt(n,t){for(var r=n.length;r--;)if(io(n[r][0],t))return r;return-1}function nr(n,t,r){var e=Gt(n,t);0>e?n.push([t,r]):n[e][1]=r}function tr(n,t,r,e){return n===B||io(n,wc[r])&&!Cc.call(e,r)?t:n}function rr(n,t,r){(r===B||io(n[t],r))&&("number"!=typeof t||r!==B||t in n)||(n[t]=r)}function er(n,t,r){var e=n[t];io(e,r)&&(!io(e,wc[t])||Cc.call(n,t))&&(r!==B||t in n)||(n[t]=r)}function ir(n,t){return n&&Se(t,oa(t),n)}function or(n,t){for(var r=-1,e=null==n,i=t.length,u=Array(i);++r<i;)u[r]=e?B:ra(n,t[r]);return u}function gr(n,t,r){return n===n&&(r!==B&&(n=r>=n?n:r),t!==B&&(n=n>=t?n:t)),n}function dr(n,t,r,e,u,o){var a;if(r&&(a=u?r(n,e,u,o):r(n)),a!==B)return a;if(!bo(n))return n;var c=nf(n);if(c){if(a=ii(n),!t)return Ae(n,a)}else{var l=ti(n),f=l==Nn||l==$n;if(l!=Tn&&l!=kn&&(!f||u))return vr[l]?oi(n,l,t):u?n:{};if(R(n))return u?n:{};if(a=ui(f?{}:n),!t)return Ne(n,ir(a,n))}o||(o=new Wt);var s=o.get(n);return s?s:(o.set(n,a),(c?i:Sr)(n,function(e,i){er(a,i,dr(e,t,r,i,n,o))}),c?a:Ne(n,a))}function yr(n){var t=oa(n),r=t.length;return function(e){if(null==e)return!r;for(var i=r;i--;){var u=t[i],o=n[u],a=e[u];if(a===B&&!(u in Object(e))||!o(a))return!1}return!0}}function mr(n,t,r){if("function"!=typeof n)throw new Mc(vn);return Pc(function(){n.apply(B,r)},t)}function _r(n,t,r,e){var i=-1,u=c,o=!0,a=n.length,s=[],h=t.length;if(!a)return s;r&&(t=f(t,k(r))),e?(u=l,o=!1):t.length>=fn&&(u=Ft,o=!1,t=new Ut(t));n:for(;++i<a;){var p=n[i],v=r?r(p):p;if(o&&v===v){for(var g=h;g--;)if(t[g]===v)continue n;s.push(p)}else u(t,v,e)||s.push(p)}return s}function br(n,t){var r=!0;return fl(n,function(n,e,i){return r=!!t(n,e,i)}),r}function wr(n,t,r,e){var i=n.length;for(r=Uo(r),0>r&&(r=-r>i?0:i+r),
+e=e===B||e>i?i:Uo(e),0>e&&(e+=i),e=r>e?0:Fo(e);e>r;)n[r++]=t;return n}function kr(n,t){var r=[];return fl(n,function(n,e,i){t(n,e,i)&&r.push(n)}),r}function Cr(n,t,r,e){e||(e=[]);for(var i=-1,u=n.length;++i<u;){var o=n[i];lo(o)&&(r||nf(o)||ao(o))?t?Cr(o,t,r,e):s(e,o):r||(e[e.length]=o)}return e}function Ar(n,t){return null==n?n:hl(n,t,aa)}function Sr(n,t){return n&&hl(n,t,oa)}function Er(n,t){return n&&pl(n,t,oa)}function jr(n,t){return a(t,function(t){return _o(n[t])})}function Dr(n,t){t=li(t,n)?[t+""]:he(t);for(var r=0,e=t.length;null!=n&&e>r;)n=n[t[r++]];return r&&r==e?n:B}function Tr(n,t){return Cc.call(n,t)||"object"==typeof n&&t in n&&null===Oc(n)}function Lr(n,t){return t in Object(n)}function Rr(n,t,r){return n>=Vc(t,r)&&n<Zc(t,r)}function Or(n,t,r){for(var e=r?l:c,i=n.length,u=i,o=Array(i),a=[];u--;){var s=n[u];u&&t&&(s=f(s,k(t))),o[u]=!r&&(t||s.length>=120)?new Ut(u&&s):B}s=n[0];var h=-1,p=s.length,v=o[0];n:for(;++h<p;){var g=s[h],d=t?t(g):g;if(!(v?Ft(v,d):e(a,d,r))){for(var u=i;--u;){var y=o[u];if(!(y?Ft(y,d):e(n[u],d,r)))continue n}v&&v.push(d),a.push(g)}}return a}function zr(n,t,e){li(t,n)||(t=he(t),n=di(n,t),t=Ii(t));var i=null==n?n:n[t];return null==i?B:r(i,n,e)}function qr(n,t,r,e,i){return n===t?!0:null==n||null==t||!bo(n)&&!wo(t)?n!==n&&t!==t:Ir(n,t,qr,r,e,i)}function Ir(n,t,r,e,i,u){var o=nf(n),a=nf(t),c=Cn,l=Cn;o||(c=ti(n),c==kn?c=Tn:c!=Tn&&(o=Oo(n))),a||(l=ti(t),l==kn?l=Tn:l!=Tn&&(a=Oo(t)));var f=c==Tn&&!R(n),s=l==Tn&&!R(t),h=c==l;if(h&&!o&&!f)return Xe(n,t,c,r,e,i);var p=i&un;if(!p){var v=f&&Cc.call(n,"__wrapped__"),g=s&&Cc.call(t,"__wrapped__");if(v||g)return r(v?n.value():n,g?t.value():t,e,i,u)}return h?(u||(u=new Wt),(o?Ve:Ke)(n,t,r,e,i,u)):!1}function Pr(n,t,r,e){var i=r.length,u=i,o=!e;if(null==n)return!u;for(n=Object(n);i--;){var a=r[i];if(o&&a[2]?a[1]!==n[a[0]]:!(a[0]in n))return!1}for(;++i<u;){a=r[i];var c=a[0],l=n[c],f=a[1];if(o&&a[2]){if(l===B&&!(c in n))return!1}else{var s=new Wt,h=e?e(l,f,c,n,t,s):B;if(!(h===B?qr(f,l,e,en|un,s):h))return!1}}return!0}function Ur(n){var t=typeof n;return"function"==t?n:null==n?Xa:"object"==t?nf(n)?Yr(n[0],n[1]):Br(n):ec(n)}function Fr(n){return Yc(Object(n))}function Hr(n){n=null==n?n:Object(n);var t=[];for(var r in n)t.push(r);return t}function Wr(n,t){var r=-1,e=co(n)?Array(n.length):[];return fl(n,function(n,i,u){e[++r]=t(n,i,u)}),e}function Br(n){var t=Ge(n);if(1==t.length&&t[0][2]){var r=t[0][0],e=t[0][1];return function(n){return null==n?!1:n[r]===e&&(e!==B||r in Object(n))}}return function(r){return r===n||Pr(r,n,t)}}function Yr(n,t){return function(r){var e=ra(r,n);return e===B&&e===t?ia(r,n):qr(t,e,B,en|un)}}function Zr(n,t,r,e,u){if(n!==t){var o=nf(t)||Oo(t)?B:aa(t);i(o||t,function(i,a){if(o&&(a=i,i=t[a]),bo(i))u||(u=new Wt),Vr(n,t,a,r,Zr,e,u);else{var c=e?e(n[a],i,a+"",n,t,u):B;c===B&&(c=i),rr(n,a,c)}})}}function Vr(n,t,r,e,i,u,o){var a=n[r],c=t[r],l=o.get(c)||o.get(a);if(l)return void rr(n,r,l);var f=u?u(a,c,r+"",n,t,o):B,s=f===B;s&&(f=c,nf(c)||Oo(c)?f=nf(a)?e?Ae(a):a:lo(a)?Ae(a):dr(c):jo(c)||ao(c)?f=ao(a)?Wo(a):!bo(a)||e&&_o(a)?dr(c):e?dr(a):a:s=!1),o.set(c,f),s&&i(f,c,e,u,o),rr(n,r,f)}function Xr(n,t,r){var e=-1,i=Qe();t=f(t.length?t:Array(1),function(n){return i(n)});var u=Wr(n,function(n,r,i){var u=f(t,function(t){return t(n)});return{criteria:u,index:++e,value:n}});return x(u,function(n,t){return $(n,t,r)})}function Kr(n,t){return n=Object(n),h(t,function(t,r){return r in n&&(t[r]=n[r]),t},{})}function Jr(n,t){var r={};return Ar(n,function(n,e){t(n,e)&&(r[e]=n)}),r}function Qr(n){return function(t){return null==t?B:t[n]}}function Gr(n){return function(t){return Dr(t,n)}}function ne(n,t){return te(n,t)}function te(n,t,r){var e=-1,i=t.length,u=n;for(r&&(u=f(n,function(n){return r(n)}));++e<i;)for(var o=0,a=t[e],c=r?r(a):a;(o=m(u,c,o))>-1;)u!==n&&Uc.call(u,o,1),Uc.call(n,o,1);return n}function re(n,t){for(var r=n?t.length:0,e=r-1;r--;){var i=t[r];if(e==r||i!=u){var u=i;if(O(i))Uc.call(n,i,1);else if(li(i,n))delete n[i];else{var o=he(i),a=di(n,o);null!=a&&delete a[Ii(o)]}}}return n}function ee(n,t){return n+Hc(Kc()*(t-n+1))}function ie(n,t,r,e){for(var i=-1,u=Zc(Fc((t-n)/(r||1)),0),o=Array(u);u--;)o[e?u:++i]=n,n+=r;return o}function ue(n,t,r,e){t=li(t,n)?[t+""]:he(t);for(var i=-1,u=t.length,o=u-1,a=n;null!=a&&++i<u;){var c=t[i];if(bo(a)){var l=r;if(i!=o){var f=a[c];l=e?e(f,c,a):B,l===B&&(l=null==f?O(t[i+1])?[]:{}:f)}er(a,c,l)}a=a[c]}return n}function oe(n,t,r){var e=-1,i=n.length;0>t&&(t=-t>i?0:i+t),r=r>i?i:r,0>r&&(r+=i),i=t>r?0:r-t>>>0,t>>>=0;for(var u=Array(i);++e<i;)u[e]=n[e+t];return u}function ae(n,t){var r;return fl(n,function(n,e,i){return r=t(n,e,i),!r}),!!r}function ce(n,t,r){var e=0,i=n?n.length:e;if("number"==typeof t&&t===t&&bn>=i){for(;i>e;){var u=e+i>>>1,o=n[u];(r?t>=o:t>o)&&null!==o?e=u+1:i=u}return i}return le(n,t,Xa,r)}function le(n,t,r,e){t=r(t);for(var i=0,u=n?n.length:0,o=t!==t,a=null===t,c=t===B;u>i;){var l=Hc((i+u)/2),f=r(n[l]),s=f!==B,h=f===f;if(o)var p=h||e;else p=a?h&&s&&(e||null!=f):c?h&&(e||s):null==f?!1:e?t>=f:t>f;p?i=l+1:u=l}return Vc(u,Mn)}function fe(n){return se(n)}function se(n,t){for(var r=0,e=n.length,i=n[0],u=t?t(i):i,o=u,a=0,c=[i];++r<e;)i=n[r],u=t?t(i):i,io(u,o)||(o=u,c[++a]=i);return c}function he(n){return nf(n)?n:mi(n)}function pe(n,t,r){var e=-1,i=c,u=n.length,o=!0,a=[],f=a;if(r)o=!1,i=l;else if(u>=fn){var s=t?null:gl(n);if(s)return P(s);o=!1,i=Ft,f=new Ut}else f=t?[]:a;n:for(;++e<u;){var h=n[e],p=t?t(h):h;if(o&&p===p){for(var v=f.length;v--;)if(f[v]===p)continue n;t&&f.push(p),a.push(h)}else i(f,p,r)||(f!==a&&f.push(p),a.push(h))}return a}function ve(n,t){t=li(t,n)?[t+""]:he(t),n=di(n,t);var r=Ii(t);return null!=n&&ea(n,r)?delete n[r]:!0}function ge(n,t,r,e){for(var i=n.length,u=e?i:-1;(e?u--:++u<i)&&t(n[u],u,n););return r?oe(n,e?0:u,e?u+1:i):oe(n,e?u+1:0,e?i:u)}function de(n,t){var r=n;return r instanceof At&&(r=r.value()),h(t,function(n,t){return t.func.apply(t.thisArg,s([n],t.args))},r)}function ye(n,t,r){for(var e=-1,i=n.length;++e<i;)var u=u?s(_r(u,n[e],t,r),_r(n[e],u,t,r)):n[e];return u&&u.length?pe(u,t,r):[]}function me(n){var t=n.constructor,r=new t(n.byteLength),e=new Tc(r);return e.set(new Tc(n)),r}function _e(t){var r=t.constructor;return h(q(t),n,new r)}function xe(n){var t=n.constructor,r=new t(n.source,gt.exec(n));return r.lastIndex=n.lastIndex,r}function Me(n){var r=n.constructor;return h(P(n),t,new r)}function be(n){return Dc?Object(ol.call(n)):{}}function we(n,t){var r=n.buffer,e=n.constructor;return new e(t?me(r):r,n.byteOffset,n.length)}function ke(n,t,r){for(var e=r.length,i=-1,u=Zc(n.length-e,0),o=-1,a=t.length,c=Array(a+u);++o<a;)c[o]=t[o];for(;++i<e;)c[r[i]]=n[i];for(;u--;)c[o++]=n[i++];return c}function Ce(n,t,r){for(var e=-1,i=r.length,u=-1,o=Zc(n.length-i,0),a=-1,c=t.length,l=Array(o+c);++u<o;)l[u]=n[u];for(var f=u;++a<c;)l[f+a]=t[a];for(;++e<i;)l[f+r[e]]=n[u++];return l}function Ae(n,t){var r=-1,e=n.length;for(t||(t=Array(e));++r<e;)t[r]=n[r];return t}function Se(n,t,r){return Ee(n,t,r)}function Ee(n,t,r,e){r||(r={});for(var i=-1,u=t.length;++i<u;){var o=t[i],a=e?e(r[o],n[o],o,r,n):n[o];er(r,o,a)}return r}function Ne(n,t){return Se(n,ml(n),t)}function $e(n,t){return function(r,e){var i=t?t():{};if(e=Qe(e),nf(r))for(var u=-1,o=r.length;++u<o;){var a=r[u];n(i,a,e(a),r)}else fl(r,function(t,r,u){n(i,t,e(t),u)});return i}}function je(n){return Xu(function(t,r){var e=-1,i=r.length,u=i>1?r[i-1]:B,o=i>2?r[2]:B;for(u="function"==typeof u?(i--,u):B,o&&ci(r[0],r[1],o)&&(u=3>i?B:u,i=1),t=Object(t);++e<i;){var a=r[e];a&&n(t,a,e,u)}return t})}function De(n,t){return function(r,e){if(null==r)return r;if(!co(r))return n(r,e);for(var i=r.length,u=t?i:-1,o=Object(r);(t?u--:++u<i)&&e(o[u],u,o)!==!1;);return r}}function Te(n){return function(t,r,e){for(var i=-1,u=Object(t),o=e(t),a=o.length;a--;){var c=o[n?a:++i];if(r(u[c],c,u)===!1)break}return t}}function Le(n,t,r){function e(){var t=this&&this!==Nr&&this instanceof e?u:n;return t.apply(i?r:this,arguments)}var i=t&Z,u=ze(n);return e}function Re(n){return function(t){t=Yo(t);var r=ar.test(t)?F(t):B,e=r?r[0]:t.charAt(0),i=r?r.slice(1).join(""):t.slice(1);return e[n]()+i}}function Oe(n){return function(t){return h(Ba(Ca(t)),n,"")}}function ze(n){return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=ll(n.prototype),e=n.apply(r,t);return bo(e)?e:r}}function qe(n,t,e){function i(){for(var o=arguments.length,a=o,c=Array(o),l=this&&this!==Nr&&this instanceof i?u:n,f=i.placeholder;a--;)c[a]=arguments[a];var s=3>o&&c[0]!==f&&c[o-1]!==f?[]:I(c,f);return o-=s.length,e>o?Be(n,t,Pe,f,B,c,s,B,B,e-o):r(l,this,c)}var u=ze(n);return i}function Ie(n){return Xu(function(t){t=Cr(t);var r=t.length,e=r,i=Ct.prototype.thru;for(n&&t.reverse();e--;){var u=t[e];if("function"!=typeof u)throw new Mc(vn);if(i&&!o&&"wrapper"==Je(u))var o=new Ct([],!0)}for(e=o?e:r;++e<r;){u=t[e];var a=Je(u),c="wrapper"==a?dl(u):B;o=c&&si(c[0])&&c[1]==(nn|K|Q|tn)&&!c[4].length&&1==c[9]?o[Je(c[0])].apply(o,c[3]):1==u.length&&si(u)?o[a]():o.thru(u)}return function(){var n=arguments,e=n[0];if(o&&1==n.length&&nf(e)&&e.length>=fn)return o.plant(e).value();for(var i=0,u=r?t[i].apply(this,n):e;++i<r;)u=t[i].call(this,u);return u}})}function Pe(n,t,r,e,i,u,o,a,c,l){function f(){for(var m=arguments.length,_=m,x=Array(m);_--;)x[_]=arguments[_];if(e&&(x=ke(x,e,i)),u&&(x=Ce(x,u,o)),v||g){var M=f.placeholder,b=I(x,M);if(m-=b.length,l>m)return Be(n,t,Pe,M,r,x,b,a,c,l-m)}var w=h?r:this,k=p?w[n]:n;return a?x=yi(x,a):d&&x.length>1&&x.reverse(),s&&c<x.length&&(x.length=c),this&&this!==Nr&&this instanceof f&&(k=y||ze(k)),k.apply(w,x)}var s=t&nn,h=t&Z,p=t&V,v=t&K,g=t&J,d=t&rn,y=p?B:ze(n);return f}function Ue(n){return Xu(function(t){return t=f(Cr(t),Qe()),Xu(function(e){var i=this;return n(t,function(n){return r(n,i,e)})})})}function Fe(n,t,r){t=Uo(t);var e=U(n);if(!t||e>=t)return"";var i=t-e;r=r===B?" ":r+"";var u=Ta(r,Fc(i/U(r)));return ar.test(r)?F(u).slice(0,i).join(""):u.slice(0,i)}function He(n,t,e,i){function u(){for(var t=-1,c=arguments.length,l=-1,f=i.length,s=Array(f+c),h=this&&this!==Nr&&this instanceof u?a:n;++l<f;)s[l]=i[l];for(;c--;)s[l++]=arguments[++t];return r(h,o?e:this,s)}var o=t&Z,a=ze(n);return u}function We(n){return function(t,r,e){return e&&"number"!=typeof e&&ci(t,r,e)&&(r=e=B),t=Ho(t),t=t===t?t:0,r===B?(r=t,t=0):r=Ho(r)||0,e=e===B?r>t?1:-1:Ho(e)||0,ie(t,r,e,n)}}function Be(n,t,r,e,i,u,o,a,c,l){var f=t&K,s=a?Ae(a):B,h=f?o:B,p=f?B:o,v=f?u:B,g=f?B:u;t|=f?Q:G,t&=~(f?G:Q),t&X||(t&=~(Z|V));var d=[n,t,i,v,h,g,p,s,c,l],y=r.apply(B,d);return si(n)&&_l(y,d),y.placeholder=e,y}function Ye(n){var t=_c[n];return function(n,r){if(n=Ho(n),r=Uo(r)){var e=(Yo(n)+"e").split("e"),i=t(e[0]+"e"+(+e[1]+r));return e=(Yo(i)+"e").split("e"),+(e[0]+"e"+(+e[1]-r))}return t(n)}}function Ze(n,t,r,e,i,u,o,a){var c=t&V;if(!c&&"function"!=typeof n)throw new Mc(vn);var l=e?e.length:0;if(l||(t&=~(Q|G),e=i=B),o=o===B?o:Zc(Uo(o),0),a=a===B?a:Uo(a),l-=i?i.length:0,t&G){var f=e,s=i;e=i=B}var h=c?B:dl(n),p=[n,t,r,e,i,f,s,u,o,a];if(h&&vi(p,h),n=p[0],t=p[1],r=p[2],e=p[3],i=p[4],a=p[9]=null==p[9]?c?0:n.length:Zc(p[9]-l,0),!a&&t&(K|J)&&(t&=~(K|J)),t&&t!=Z)v=t==K||t==J?qe(n,t,a):t!=Q&&t!=(Z|Q)||i.length?Pe.apply(B,p):He(n,t,r,e);else var v=Le(n,t,r);var g=h?vl:_l;return g(v,p)}function Ve(n,t,r,e,i,u){var o=-1,a=i&un,c=i&en,l=n.length,f=t.length;if(l!=f&&!(a&&f>l))return!1;var s=u.get(n);if(s)return s==t;var h=!0;for(u.set(n,t);++o<l;){var p=n[o],g=t[o];if(e)var d=a?e(g,p,o,t,n,u):e(p,g,o,n,t,u);if(d!==B){if(d)continue;h=!1;break}if(c){if(!v(t,function(n){return p===n||r(p,n,e,i,u)})){h=!1;break}}else if(p!==g&&!r(p,g,e,i,u)){h=!1;break}}return u["delete"](n),h}function Xe(n,t,r,e,i,u){switch(r){case In:return!(n.byteLength!=t.byteLength||!e(new Tc(n),new Tc(t)));case An:case Sn:return+n==+t;case En:return n.name==t.name&&n.message==t.message;case Dn:return n!=+n?t!=+t:n==+t;case Ln:case On:return n==t+"";case jn:var o=q;case Rn:var a=u&un;return o||(o=P),(a||n.size==t.size)&&e(o(n),o(t),i,u|en);case zn:return!!Dc&&ol.call(n)==ol.call(t)}return!1}function Ke(n,t,r,e,i,u){var o=i&un,a=oa(n),c=a.length,l=oa(t),f=l.length;if(c!=f&&!o)return!1;for(var s=c;s--;){var h=a[s];if(!(o?h in t:Tr(t,h)))return!1}var p=u.get(n);if(p)return p==t;var v=!0;u.set(n,t);for(var g=o;++s<c;){h=a[s];var d=n[h],y=t[h];if(e)var m=o?e(y,d,h,t,n,u):e(d,y,h,n,t,u);if(!(m===B?d===y||r(d,y,e,i,u):m)){v=!1;break}g||(g="constructor"==h)}if(v&&!g){var _=n.constructor,x=t.constructor;_!=x&&"constructor"in n&&"constructor"in t&&!("function"==typeof _&&_ instanceof _&&"function"==typeof x&&x instanceof x)&&(v=!1)}return u["delete"](n),v}function Je(n){for(var t=n.name+"",r=cl[t],e=Cc.call(cl,t)?r.length:0;e--;){var i=r[e],u=i.func;if(null==u||u==n)return i.name}return t}function Qe(){var n=qn.iteratee||Ka;return n=n===Ka?Ur:n,arguments.length?n(arguments[0],arguments[1]):n}function Ge(n){for(var t=ga(n),r=t.length;r--;)t[r][2]=pi(t[r][1]);return t}function ni(n,t){var r=null==n?B:n[t];return So(r)?r:B}function ti(n){return Ec.call(n)}function ri(n,t,r){for(var e=-1,i=r.length;++e<i;){var u=r[e],o=u.size;switch(u.type){case"drop":n+=o;break;case"dropRight":t-=o;break;case"take":t=Vc(t,n+o);break;case"takeRight":n=Zc(n,t-o)}}return{start:n,end:t}}function ei(n,t,r){if(null==n)return!1;var e=r(n,t);return e||li(t)||(t=he(t),n=di(n,t),null!=n&&(t=Ii(t),e=r(n,t))),e||Mo(n&&n.length)&&O(t,n.length)&&(nf(n)||Lo(n)||ao(n))}function ii(n){var t=n.length,r=n.constructor(t);return t&&"string"==typeof n[0]&&Cc.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function ui(n){var t=n.constructor;return ll(_o(t)?t.prototype:B)}function oi(n,t,r){var e=n.constructor;switch(t){case In:return me(n);case An:case Sn:return new e(+n);case Pn:case Un:case Fn:case Hn:case Wn:case Bn:case Yn:case Zn:case Vn:return we(n,r);case jn:return _e(n);case Dn:case On:return new e(n);case Ln:return xe(n);case Rn:return Me(n);case zn:return be(n)}}function ai(n){var t=n?n.length:B;return Mo(t)&&(nf(n)||Lo(n)||ao(n))?b(t,String):null}function ci(n,t,r){if(!bo(r))return!1;var e=typeof t;return("number"==e?co(r)&&O(t,r.length):"string"==e&&t in r)?io(r[t],n):!1}function li(n,t){return"number"==typeof n?!0:!nf(n)&&(ot.test(n)||!ut.test(n)||null!=t&&n in Object(t))}function fi(n){var t=typeof n;return"number"==t||"boolean"==t||"string"==t&&"__proto__"!==n||null==n}function si(n){var t=Je(n),r=qn[t];if("function"!=typeof r||!(t in At.prototype))return!1;if(n===r)return!0;var e=dl(r);return!!e&&n===e[0]}function hi(n){var t=n&&n.constructor,r="function"==typeof t&&t.prototype||wc;return n===r}function pi(n){return n===n&&!bo(n)}function vi(n,t){var r=n[1],e=t[1],i=r|e,u=(Z|V|nn)>i,o=e==nn&&r==K||e==nn&&r==tn&&n[7].length<=t[8]||e==(nn|tn)&&t[7].length<=t[8]&&r==K;if(!u&&!o)return n;e&Z&&(n[2]=t[2],i|=r&Z?0:X);var a=t[3];if(a){var c=n[3];n[3]=c?ke(c,a,t[4]):Ae(a),n[4]=c?I(n[3],wn):Ae(t[4])}return a=t[5],a&&(c=n[5],n[5]=c?Ce(c,a,t[6]):Ae(a),n[6]=c?I(n[5],wn):Ae(t[6])),a=t[7],a&&(n[7]=Ae(a)),e&nn&&(n[8]=null==n[8]?t[8]:Vc(n[8],t[8])),null==n[9]&&(n[9]=t[9]),n[0]=t[0],n[1]=i,n}function gi(n,t,r,e,i,u){return bo(n)&&bo(t)&&(u.set(t,n),Zr(n,t,B,gi,u)),n}function di(n,t){return 1==t.length?n:ra(n,oe(t,0,-1))}function yi(n,t){for(var r=n.length,e=Vc(t.length,r),i=Ae(n);e--;){var u=t[e];n[e]=O(u,r)?i[u]:B}return n}function mi(n){var t=[];return Yo(n).replace(at,function(n,r,e,i){t.push(e?i.replace(pt,"$1"):r||n)}),t}function _i(n){return lo(n)?n:[]}function xi(n){return"function"==typeof n?n:Xa}function Mi(n){if(n instanceof At)return n.clone();var t=new Ct(n.__wrapped__,n.__chain__);return t.__actions__=Ae(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function bi(n,t){t=Zc(Uo(t),0);var r=n?n.length:0;if(!r||1>t)return[];for(var e=0,i=-1,u=Array(Fc(r/t));r>e;)u[++i]=oe(n,e,e+=t);return u}function wi(n){for(var t=-1,r=n?n.length:0,e=-1,i=[];++t<r;){var u=n[t];u&&(i[++e]=u)}return i}function ki(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),oe(n,0>t?0:t,e)):[]}function Ci(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),t=e-t,oe(n,0,0>t?0:t)):[]}function Ai(n,t){return n&&n.length?ge(n,Qe(t,3),!0,!0):[]}function Si(n,t){return n&&n.length?ge(n,Qe(t,3),!0):[]}function Ei(n,t,r,e){var i=n?n.length:0;return i?(r&&"number"!=typeof r&&ci(n,t,r)&&(r=0,e=i),wr(n,t,r,e)):[]}function Ni(n,t){return n&&n.length?y(n,Qe(t,3)):-1}function $i(n,t){return n&&n.length?y(n,Qe(t,3),!0):-1}function ji(n,t){var r=n?n.length:0;return r?Cr(f(n,Qe(t,3))):[]}function Di(n){var t=n?n.length:0;return t?Cr(n):[]}function Ti(n){var t=n?n.length:0;return t?Cr(n,!0):[]}function Li(n){for(var t=-1,r=n?n.length:0,e={};++t<r;){var i=n[t];e[i[0]]=i[1]}return e}function Ri(n){return n?n[0]:B}function Oi(n,t,r){var e=n?n.length:0;return e?(r=Uo(r),0>r&&(r=Zc(e+r,0)),m(n,t,r)):-1}function zi(n){return Ci(n,1)}function qi(n,t){return n?Bc.call(n,t):""}function Ii(n){var t=n?n.length:0;return t?n[t-1]:B}function Pi(n,t,r){var e=n?n.length:0;if(!e)return-1;var i=e;if(r!==B&&(i=Uo(r),i=(0>i?Zc(e+i,0):Vc(i,e-1))+1),t!==t)return L(n,i,!0);for(;i--;)if(n[i]===t)return i;return-1}function Ui(n,t){return n&&n.length&&t&&t.length?ne(n,t):n}function Fi(n,t,r){return n&&n.length&&t&&t.length?te(n,t,Qe(r)):n}function Hi(n,t){var r=[];if(!n||!n.length)return r;var e=-1,i=[],u=n.length;for(t=Qe(t,3);++e<u;){var o=n[e];t(o,e,n)&&(r.push(o),i.push(e))}return re(n,i),r}function Wi(n){return n?Jc.call(n):n}function Bi(n,t,r){var e=n?n.length:0;return e?(r&&"number"!=typeof r&&ci(n,t,r)?(t=0,r=e):(t=null==t?0:Uo(t),r=r===B?e:Uo(r)),oe(n,t,r)):[]}function Yi(n,t){return ce(n,t)}function Zi(n,t,r){return le(n,t,Qe(r))}function Vi(n,t){var r=n?n.length:0;if(r){var e=ce(n,t);if(r>e&&io(n[e],t))return e}return-1}function Xi(n,t){return ce(n,t,!0)}function Ki(n,t,r){return le(n,t,Qe(r),!0)}function Ji(n,t){var r=n?n.length:0;if(r){var e=ce(n,t,!0)-1;if(io(n[e],t))return e}return-1}function Qi(n){return n&&n.length?fe(n):[]}function Gi(n,t){return n&&n.length?se(n,Qe(t)):[]}function nu(n){return ki(n,1)}function tu(n,t,r){return n&&n.length?(t=r||t===B?1:Uo(t),oe(n,0,0>t?0:t)):[]}function ru(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),t=e-t,oe(n,0>t?0:t,e)):[]}function eu(n,t){return n&&n.length?ge(n,Qe(t,3),!1,!0):[]}function iu(n,t){return n&&n.length?ge(n,Qe(t,3)):[]}function uu(n){return n&&n.length?pe(n):[]}function ou(n,t){return n&&n.length?pe(n,Qe(t)):[]}function au(n,t){return n&&n.length?pe(n,B,t):[]}function cu(n){if(!n||!n.length)return[];var t=0;return n=a(n,function(n){return lo(n)?(t=Zc(n.length,t),!0):void 0}),b(t,function(t){return f(n,Qr(t))})}function lu(n,t){if(!n||!n.length)return[];var e=cu(n);return null==t?e:f(e,function(n){return r(t,B,n)})}function fu(n,t){for(var r=-1,e=n?n.length:0,i=t?t.length:0,u={};++r<e;)ue(u,n[r],i>r?t[r]:B);return u}function su(n){var t=qn(n);return t.__chain__=!0,t}function hu(n,t){return t(n),n}function pu(n,t){return t(n)}function vu(){return su(this)}function gu(){return new Ct(this.value(),this.__chain__)}function du(n){return this.map(n).flatten()}function yu(){this.__values__===B&&(this.__values__=Po(this.value()));var n=this.__index__>=this.__values__.length,t=n?B:this.__values__[this.__index__++];return{done:n,value:t}}function mu(){return this}function _u(n){for(var t,r=this;r instanceof Mt;){var e=Mi(r);e.__index__=0,e.__values__=B,t?i.__wrapped__=e:t=e;var i=e;r=r.__wrapped__}return i.__wrapped__=n,t}function xu(){var n=this.__wrapped__;if(n instanceof At){var t=n;return this.__actions__.length&&(t=new At(this)),t=t.reverse(),t.__actions__.push({func:pu,args:[Wi],thisArg:B}),new Ct(t,this.__chain__)}return this.thru(Wi)}function Mu(){return de(this.__wrapped__,this.__actions__)}function bu(n,t,r){var e=nf(n)?o:br;return r&&ci(n,t,r)&&(t=B),e(n,Qe(t,3))}function wu(n,t){var r=nf(n)?a:kr;return r(n,Qe(t,3))}function ku(n,t){if(t=Qe(t,3),nf(n)){var r=y(n,t);return r>-1?n[r]:B}return d(n,t,fl)}function Cu(n,t){if(t=Qe(t,3),nf(n)){var r=y(n,t,!0);return r>-1?n[r]:B}return d(n,t,sl)}function Au(n,t){return"function"==typeof t&&nf(n)?i(n,t):fl(n,xi(t))}function Su(n,t){return"function"==typeof t&&nf(n)?u(n,t):sl(n,xi(t))}function Eu(n,t,r,e){n=co(n)?n:_a(n),r=r&&!e?Uo(r):0;var i=n.length;return 0>r&&(r=Zc(i+r,0)),Lo(n)?i>=r&&n.indexOf(t,r)>-1:!!i&&m(n,t,r)>-1}function Nu(n,t){var r=nf(n)?f:Wr;return r(n,Qe(t,3))}function $u(n,t,r,e){return null==n?[]:(nf(t)||(t=null==t?[]:[t]),r=e?B:r,nf(r)||(r=null==r?[]:[r]),Xr(n,t,r))}function ju(n,t,r){var e=nf(n)?h:_,i=arguments.length<3;return e(n,Qe(t,4),r,i,fl)}function Du(n,t,r){var e=nf(n)?p:_,i=arguments.length<3;return e(n,Qe(t,4),r,i,sl)}function Tu(n,t){var r=nf(n)?a:kr;return t=Qe(t,3),r(n,function(n,r,e){return!t(n,r,e)})}function Lu(n){var t=co(n)?n:_a(n),r=t.length;return r>0?t[ee(0,r-1)]:B}function Ru(n,t){var r=-1,e=Po(n),i=e.length,u=i-1;for(t=gr(Uo(t),0,i);++r<t;){var o=ee(r,u),a=e[o];e[o]=e[r],e[r]=a}return e.length=t,e}function Ou(n){return Ru(n,xn)}function zu(n){if(null==n)return 0;if(co(n)){var t=n.length;return t&&Lo(n)?U(n):t}return oa(n).length}function qu(n,t,r){var e=nf(n)?v:ae;return r&&ci(n,t,r)&&(t=B),e(n,Qe(t,3))}function Iu(n,t){if("function"!=typeof t)throw new Mc(vn);return n=Uo(n),function(){return--n<1?t.apply(this,arguments):void 0}}function Pu(n,t,r){return t=r?B:t,t=n&&null==t?n.length:t,Ze(n,nn,B,B,B,B,t)}function Uu(n,t){var r;if("function"!=typeof t)throw new Mc(vn);return n=Uo(n),function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=B),r}}function Fu(n,t,r){t=r?B:t;var e=Ze(n,K,B,B,B,B,B,t);return e.placeholder=Fu.placeholder,e}function Hu(n,t,r){t=r?B:t;var e=Ze(n,J,B,B,B,B,B,t);return e.placeholder=Hu.placeholder,e}function Wu(n,t,r){function e(){v&&Lc(v),f&&Lc(f),d=0,l=f=p=v=g=B}function i(t,r){r&&Lc(r),f=v=g=B,t&&(d=Bl(),s=n.apply(p,l),v||f||(l=p=B))}function u(){var n=t-(Bl()-h);0>=n||n>t?i(g,f):v=Pc(u,n)}function o(){return(v&&g||f&&_)&&(s=n.apply(p,l)),e(),s}function a(){i(_,v)}function c(){if(l=arguments,h=Bl(),p=this,g=_&&(v||!y),m===!1)var r=y&&!v;else{f||y||(d=h);var e=m-(h-d),i=0>=e||e>m;i?(f&&(f=Lc(f)),d=h,s=n.apply(p,l)):f||(f=Pc(a,e))}return i&&v?v=Lc(v):v||t===m||(v=Pc(u,t)),r&&(i=!0,s=n.apply(p,l)),!i||v||f||(l=p=B),s}var l,f,s,h,p,v,g,d=0,y=!1,m=!1,_=!0;if("function"!=typeof n)throw new Mc(vn);return t=Ho(t)||0,bo(r)&&(y=!!r.leading,m="maxWait"in r&&Zc(Ho(r.maxWait)||0,t),_="trailing"in r?!!r.trailing:_),c.cancel=e,c.flush=o,c}function Bu(n){return Ze(n,rn)}function Yu(n,t){if("function"!=typeof n||t&&"function"!=typeof t)throw new Mc(vn);var r=function(){var e=arguments,i=t?t.apply(this,e):e[0],u=r.cache;if(u.has(i))return u.get(i);var o=n.apply(this,e);return r.cache=u.set(i,o),o};return r.cache=new Yu.Cache,r}function Zu(n){if("function"!=typeof n)throw new Mc(vn);return function(){return!n.apply(this,arguments)}}function Vu(n){return Uu(2,n)}function Xu(n,t){if("function"!=typeof n)throw new Mc(vn);return t=Zc(t===B?n.length-1:Uo(t),0),function(){for(var e=arguments,i=-1,u=Zc(e.length-t,0),o=Array(u);++i<u;)o[i]=e[t+i];switch(t){case 0:return n.call(this,o);case 1:return n.call(this,e[0],o);case 2:return n.call(this,e[0],e[1],o)}var a=Array(t+1);for(i=-1;++i<t;)a[i]=e[i];return a[t]=o,r(n,this,a)}}function Ku(n){if("function"!=typeof n)throw new Mc(vn);return function(t){return r(n,this,t)}}function Ju(n,t,r){var e=!0,i=!0;if("function"!=typeof n)throw new Mc(vn);return bo(r)&&(e="leading"in r?!!r.leading:e,i="trailing"in r?!!r.trailing:i),Wu(n,t,{leading:e,maxWait:t,trailing:i})}function Qu(n){return Pu(n,1)}function Gu(n,t){return t=null==t?Xa:t,Jl(t,n)}function no(n){return dr(n)}function to(n,t){return dr(n,!1,t)}function ro(n){return dr(n,!0)}function eo(n,t){return dr(n,!0,t)}function io(n,t){return n===t||n!==n&&t!==t}function uo(n,t){return n>t}function oo(n,t){return n>=t}function ao(n){return lo(n)&&Cc.call(n,"callee")&&(!Ic.call(n,"callee")||Ec.call(n)==kn)}function co(n){return null!=n&&!("function"==typeof n&&_o(n))&&Mo(yl(n))}function lo(n){return wo(n)&&co(n)}function fo(n){return n===!0||n===!1||wo(n)&&Ec.call(n)==An}function so(n){return wo(n)&&Ec.call(n)==Sn}function ho(n){return!!n&&1===n.nodeType&&wo(n)&&!jo(n)}function po(n){return!wo(n)||_o(n.splice)?!zu(n):!oa(n).length}function vo(n,t){return qr(n,t)}function go(n,t,r){r="function"==typeof r?r:B;var e=r?r(n,t):B;return e===B?qr(n,t,r):!!e}function yo(n){return wo(n)&&"string"==typeof n.message&&Ec.call(n)==En}function mo(n){return"number"==typeof n&&Wc(n)}function _o(n){var t=bo(n)?Ec.call(n):"";return t==Nn||t==$n}function xo(n){return"number"==typeof n&&n==Uo(n)}function Mo(n){return"number"==typeof n&&n>-1&&n%1==0&&yn>=n}function bo(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function wo(n){return!!n&&"object"==typeof n}function ko(n,t){return n===t||Pr(n,t,Ge(t))}function Co(n,t,r){return r="function"==typeof r?r:B,Pr(n,t,Ge(t),r)}function Ao(n){return $o(n)&&n!=+n}function So(n){return null==n?!1:_o(n)?$c.test(kc.call(n)):wo(n)&&(R(n)?$c:_t).test(n)}function Eo(n){return null===n}function No(n){return null==n}function $o(n){return"number"==typeof n||wo(n)&&Ec.call(n)==Dn}function jo(n){if(!wo(n)||Ec.call(n)!=Tn||R(n))return!1;var t=wc;if("function"==typeof n.constructor&&(t=Oc(n)),null===t)return!0;var r=t.constructor;return"function"==typeof r&&r instanceof r&&kc.call(r)==Sc}function Do(n){return bo(n)&&Ec.call(n)==Ln}function To(n){return xo(n)&&n>=-yn&&yn>=n}function Lo(n){return"string"==typeof n||!nf(n)&&wo(n)&&Ec.call(n)==On}function Ro(n){return"symbol"==typeof n||wo(n)&&Ec.call(n)==zn}function Oo(n){return wo(n)&&Mo(n.length)&&!!pr[Ec.call(n)]}function zo(n){return n===B}function qo(n,t){return t>n}function Io(n,t){return t>=n}function Po(n){if(!n)return[];if(co(n))return Lo(n)?F(n):Ae(n);if(qc&&n[qc])return z(n[qc]());var t=ti(n),r=t==jn?q:t==Rn?P:_a;return r(n)}function Uo(n){if(!n)return 0===n?n:0;if(n=Ho(n),n===dn||n===-dn){var t=0>n?-1:1;return t*mn}var r=n%1;return n===n?r?n-r:n:0}function Fo(n){return n?gr(Uo(n),0,xn):0}function Ho(n){if(bo(n)){var t=_o(n.valueOf)?n.valueOf():n;n=bo(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(ft,"");var r=mt.test(n);return r||xt.test(n)?Mr(n.slice(2),r?2:8):yt.test(n)?_n:+n}function Wo(n){return Se(n,aa(n))}function Bo(n){return gr(Uo(n),-yn,yn)}function Yo(n){if("string"==typeof n)return n;if(null==n)return"";if(Ro(n))return Dc?al.call(n):"";var t=n+"";return"0"==t&&1/n==-dn?"-0":t}function Zo(n,t){var r=ll(n);return t?ir(r,t):r}function Vo(n,t){return d(n,Qe(t,3),Sr,!0)}function Xo(n,t){return d(n,Qe(t,3),Er,!0)}function Ko(n,t){return null==n?n:hl(n,xi(t),aa)}function Jo(n,t){return null==n?n:pl(n,xi(t),aa)}function Qo(n,t){return n&&Sr(n,xi(t))}function Go(n,t){return n&&Er(n,xi(t))}function na(n){return null==n?[]:jr(n,oa(n))}function ta(n){return null==n?[]:jr(n,aa(n))}function ra(n,t,r){var e=null==n?B:Dr(n,t);return e===B?r:e}function ea(n,t){return ei(n,t,Tr)}function ia(n,t){return ei(n,t,Lr)}function ua(n,t,r){return h(oa(n),function(e,i){var u=n[i];return t&&!r?Cc.call(e,u)?e[u].push(i):e[u]=[i]:e[u]=i,e},{})}function oa(n){var t=hi(n);if(!t&&!co(n))return Fr(n);var r=ai(n),e=!!r,i=r||[],u=i.length;for(var o in n)!Tr(n,o)||e&&("length"==o||O(o,u))||t&&"constructor"==o||i.push(o);return i}function aa(n){for(var t=-1,r=hi(n),e=Hr(n),i=e.length,u=ai(n),o=!!u,a=u||[],c=a.length;++t<i;){var l=e[t];o&&("length"==l||O(l,c))||"constructor"==l&&(r||!Cc.call(n,l))||a.push(l)}return a}function ca(n,t){var r={};return t=Qe(t,3),Sr(n,function(n,e,i){r[t(n,e,i)]=n}),r}function la(n,t){var r={};return t=Qe(t,3),Sr(n,function(n,e,i){r[e]=t(n,e,i)}),r}function fa(n,t){return t=Qe(t,2),Jr(n,function(n,r){return!t(n,r)})}function sa(n,t){return null==n?{}:Jr(n,Qe(t,2))}function ha(n,t,r){if(li(t,n))e=null==n?B:n[t];else{t=he(t);var e=ra(n,t);n=di(n,t)}return e===B&&(e=r),_o(e)?e.call(n):e}function pa(n,t,r){return null==n?n:ue(n,t,r)}function va(n,t,r,e){return e="function"==typeof e?e:B,null==n?n:ue(n,t,r,e)}function ga(n){return w(n,oa(n))}function da(n){return w(n,aa(n))}function ya(n,t,r){var e=nf(n)||Oo(n);if(t=Qe(t,4),null==r)if(e||bo(n)){var u=n.constructor;r=e?nf(n)?new u:[]:ll(_o(u)?u.prototype:B)}else r={};return(e?i:Sr)(n,function(n,e,i){return t(r,n,e,i)}),r}function ma(n,t){return null==n?!0:ve(n,t)}function _a(n){return n?C(n,oa(n)):[]}function xa(n){return null==n?C(n,aa(n)):[]}function Ma(n,t,r){return r===B&&(r=t,t=B),r!==B&&(r=Ho(r),r=r===r?r:0),t!==B&&(t=Ho(t),t=t===t?t:0),gr(Ho(n),t,r)}function ba(n,t,r){return t=Ho(t)||0,r===B?(r=t,t=0):r=Ho(r)||0,n=Ho(n),Rr(n,t,r)}function wa(n,t,r){if(r&&"boolean"!=typeof r&&ci(n,t,r)&&(t=r=B),r===B&&("boolean"==typeof t?(r=t,t=B):"boolean"==typeof n&&(r=n,n=B)),n===B&&t===B?(n=0,t=1):(n=Ho(n)||0,t===B?(t=n,n=0):t=Ho(t)||0),n>t){var e=n;n=t,t=e}if(r||n%1||t%1){var i=Kc();return Vc(n+i*(t-n+xr("1e-"+((i+"").length-1))),t)}return ee(n,t)}function ka(n){return mf(Yo(n).toLowerCase())}function Ca(n){return n=Yo(n),n&&n.replace(bt,j).replace(ur,"")}function Aa(n,t,r){n=Yo(n),t="string"==typeof t?t:t+"";var e=n.length;return r=r===B?e:gr(Uo(r),0,e),r-=t.length,r>=0&&n.indexOf(t,r)==r}function Sa(n){return n=Yo(n),n&&tt.test(n)?n.replace(Gn,D):n}function Ea(n){return n=Yo(n),n&&lt.test(n)?n.replace(ct,"\\$&"):n}function Na(n,t,r){n=Yo(n),t=Uo(t);var e=U(n);if(!t||e>=t)return n;var i=(t-e)/2,u=Hc(i),o=Fc(i);return Fe("",u,r)+n+Fe("",o,r)}function $a(n,t,r){return n=Yo(n),n+Fe(n,t,r)}function ja(n,t,r){return n=Yo(n),Fe(n,t,r)+n}function Da(n,t,r){return r||null==t?t=0:t&&(t=+t),n=Yo(n).replace(ft,""),Xc(n,t||(dt.test(n)?16:10))}function Ta(n,t){n=Yo(n),t=Uo(t);var r="";if(!n||1>t||t>yn)return r;do t%2&&(r+=n),t=Hc(t/2),n+=n;while(t);return r}function La(){var n=arguments,t=Yo(n[0]);return n.length<3?t:t.replace(n[1],n[2])}function Ra(n,t,r){return Yo(n).split(t,r)}function Oa(n,t,r){return n=Yo(n),r=gr(Uo(r),0,n.length),n.lastIndexOf(t,r)==r}function za(n,t,r){var e=qn.templateSettings;r&&ci(n,t,r)&&(t=B),n=Yo(n),t=ef({},t,e,tr);var i,u,o=ef({},t.imports,e.imports,tr),a=oa(o),c=C(o,a),l=0,f=t.interpolate||wt,s="__p += '",h=xc((t.escape||wt).source+"|"+f.source+"|"+(f===it?vt:wt).source+"|"+(t.evaluate||wt).source+"|$","g"),p="//# sourceURL="+("sourceURL"in t?t.sourceURL:"lodash.templateSources["+ ++hr+"]")+"\n";n.replace(h,function(t,r,e,o,a,c){return e||(e=o),s+=n.slice(l,c).replace(kt,T),r&&(i=!0,s+="' +\n__e("+r+") +\n'"),a&&(u=!0,s+="';\n"+a+";\n__p += '"),e&&(s+="' +\n((__t = ("+e+")) == null ? '' : __t) +\n'"),l=c+t.length,t}),s+="';\n";var v=t.variable;v||(s="with (obj) {\n"+s+"\n}\n"),s=(u?s.replace(Xn,""):s).replace(Kn,"$1").replace(Jn,"$1;"),s="function("+(v||"obj")+") {\n"+(v?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(i?", __e = _.escape":"")+(u?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+s+"return __p\n}";var g=bf(function(){return Function(a,p+"return "+s).apply(B,c)});if(g.source=s,yo(g))throw g;return g}function qa(n){return Yo(n).toLowerCase()}function Ia(n){return Yo(n).toUpperCase()}function Pa(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(ft,"");if(t+="",!t)return n;var e=F(n),i=F(t);return e.slice(A(e,i),S(e,i)+1).join("")}function Ua(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(ht,"");if(t+="",!t)return n;var e=F(n);return e.slice(0,S(e,F(t))+1).join("")}function Fa(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(st,"");if(t+="",!t)return n;var e=F(n);return e.slice(A(e,F(t))).join("")}function Ha(n,t){var r=on,e=an;if(bo(t)){var i="separator"in t?t.separator:i;r="length"in t?Uo(t.length):r,e="omission"in t?Yo(t.omission):e}n=Yo(n);var u=n.length;if(ar.test(n)){var o=F(n);u=o.length}if(r>=u)return n;var a=r-U(e);if(1>a)return e;var c=o?o.slice(0,a).join(""):n.slice(0,a);if(i===B)return c+e;if(o&&(a+=c.length-a),
+Do(i)){if(n.slice(a).search(i)){var l,f=c;for(i.global||(i=xc(i.source,Yo(gt.exec(i))+"g")),i.lastIndex=0;l=i.exec(f);)var s=l.index;c=c.slice(0,s===B?a:s)}}else if(n.indexOf(i,a)!=a){var h=c.lastIndexOf(i);h>-1&&(c=c.slice(0,h))}return c+e}function Wa(n){return n=Yo(n),n&&nt.test(n)?n.replace(Qn,H):n}function Ba(n,t,r){return n=Yo(n),t=r?B:t,t===B&&(t=fr.test(n)?lr:cr),n.match(t)||[]}function Ya(n){var t=n?n.length:0,e=Qe();return n=t?f(n,function(n){if("function"!=typeof n[1])throw new Mc(vn);return[e(n[0]),n[1]]}):[],Xu(function(e){for(var i=-1;++i<t;){var u=n[i];if(r(u[0],this,e))return r(u[1],this,e)}})}function Za(n){return yr(dr(n,!0))}function Va(n){return function(){return n}}function Xa(n){return n}function Ka(n){return wo(n)&&!nf(n)?Ja(n):Ur(n)}function Ja(n){return Br(dr(n,!0))}function Qa(n,t){return Yr(n,dr(t,!0))}function Ga(n,t,r){var e=oa(t),u=jr(t,e);null!=r||bo(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=jr(t,oa(t)));var o=bo(r)&&"chain"in r?r.chain:!0,a=_o(n);return i(u,function(r){var e=t[r];n[r]=e,a&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__),i=r.__actions__=Ae(this.__actions__);return i.push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,s([this.value()],arguments))})}),n}function nc(){return Nr._===this&&(Nr._=Nc),this}function tc(){}function rc(n){return n=Uo(n),function(){return arguments[n]}}function ec(n){return li(n)?Qr(n):Gr(n)}function ic(n){return function(t){return null==n?B:Dr(n,t)}}function uc(n,t){if(n=Uo(n),1>n||n>yn)return[];var r=xn,e=Vc(n,xn);t=xi(t),n-=xn;for(var i=b(e,t);++r<n;)t(r);return i}function oc(n){return nf(n)?f(n,String):mi(n)}function ac(n){var t=++Ac;return Yo(n)+t}function cc(n,t){var r;return n!==B&&(r=n),t!==B&&(r=r===B?t:r+t),r}function lc(n){return n&&n.length?g(n,Xa,uo):B}function fc(n,t){return n&&n.length?g(n,Qe(t),uo):B}function sc(n){return gc(n)/(n?n.length:0)}function hc(n){return n&&n.length?g(n,Xa,qo):B}function pc(n,t){return n&&n.length?g(n,Qe(t),qo):B}function vc(n,t){var r;return n!==B&&(r=n),t!==B&&(r=r===B?t:r-t),r}function gc(n){return n&&n.length?M(n,Xa):B}function dc(n,t){return n&&n.length?M(n,Qe(t)):B}E=E?$r.defaults({},E,$r.pick(Nr,sr)):Nr;var yc=E.Date,mc=E.Error,_c=E.Math,xc=E.RegExp,Mc=E.TypeError,bc=E.Array.prototype,wc=E.Object.prototype,kc=E.Function.prototype.toString,Cc=wc.hasOwnProperty,Ac=0,Sc=kc.call(Object),Ec=wc.toString,Nc=Nr._,$c=xc("^"+kc.call(Cc).replace(ct,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),jc=E.Reflect,Dc=E.Symbol,Tc=E.Uint8Array,Lc=E.clearTimeout,Rc=jc?jc.enumerate:B,Oc=Object.getPrototypeOf,zc=Object.getOwnPropertySymbols,qc="symbol"==typeof(qc=Dc&&Dc.iterator)?qc:B,Ic=wc.propertyIsEnumerable,Pc=E.setTimeout,Uc=bc.splice,Fc=_c.ceil,Hc=_c.floor,Wc=E.isFinite,Bc=bc.join,Yc=Object.keys,Zc=_c.max,Vc=_c.min,Xc=E.parseInt,Kc=_c.random,Jc=bc.reverse,Qc=ni(E,"Map"),Gc=ni(E,"Set"),nl=ni(E,"WeakMap"),tl=ni(Object,"create"),rl=nl&&new nl,el=Qc?kc.call(Qc):"",il=Gc?kc.call(Gc):"",ul=Dc?Dc.prototype:B,ol=Dc?ul.valueOf:B,al=Dc?ul.toString:B,cl={};qn.templateSettings={escape:rt,evaluate:et,interpolate:it,variable:"",imports:{_:qn}};var ll=function(){function n(){}return function(t){if(bo(t)){n.prototype=t;var r=new n;n.prototype=B}return r||{}}}(),fl=De(Sr),sl=De(Er,!0),hl=Te(),pl=Te(!0);Rc&&!Ic.call({valueOf:1},"valueOf")&&(Hr=function(n){return z(Rc(n))});var vl=rl?function(n,t){return rl.set(n,t),n}:Xa,gl=Gc&&2===new Gc([1,2]).size?function(n){return new Gc(n)}:tc,dl=rl?function(n){return rl.get(n)}:tc,yl=Qr("length"),ml=zc||function(){return[]};(Qc&&ti(new Qc)!=jn||Gc&&ti(new Gc)!=Rn)&&(ti=function(n){var t=Ec.call(n),r=t==Tn?n.constructor:null,e="function"==typeof r?kc.call(r):"";if(e){if(e==el)return jn;if(e==il)return Rn}return t});var _l=function(){var n=0,t=0;return function(r,e){var i=Bl(),u=ln-(i-t);if(t=i,u>0){if(++n>=cn)return r}else n=0;return vl(r,e)}}(),xl=Xu(function(n,t){return nf(n)||(n=null==n?[]:[Object(n)]),t=Cr(t),e(n,t)}),Ml=Xu(function(n,t){return lo(n)?_r(n,Cr(t,!1,!0)):[]}),bl=Xu(function(n,t){var r=Ii(t);return lo(r)&&(r=B),lo(n)?_r(n,Cr(t,!1,!0),Qe(r)):[]}),wl=Xu(function(n,t){var r=Ii(t);return lo(r)&&(r=B),lo(n)?_r(n,Cr(t,!1,!0),B,r):[]}),kl=Xu(function(n){var t=f(n,_i);return t.length&&t[0]===n[0]?Or(t):[]}),Cl=Xu(function(n){var t=Ii(n),r=f(n,_i);return t===Ii(r)?t=B:r.pop(),r.length&&r[0]===n[0]?Or(r,Qe(t)):[]}),Al=Xu(function(n){var t=Ii(n),r=f(n,_i);return t===Ii(r)?t=B:r.pop(),r.length&&r[0]===n[0]?Or(r,B,t):[]}),Sl=Xu(Ui),El=Xu(function(n,t){t=f(Cr(t),String);var r=or(n,t);return re(n,t.sort(N)),r}),Nl=Xu(function(n){return pe(Cr(n,!1,!0))}),$l=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),pe(Cr(n,!1,!0),Qe(t))}),jl=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),pe(Cr(n,!1,!0),B,t)}),Dl=Xu(function(n,t){return lo(n)?_r(n,t):[]}),Tl=Xu(function(n){return ye(a(n,lo))}),Ll=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),ye(a(n,lo),Qe(t))}),Rl=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),ye(a(n,lo),B,t)}),Ol=Xu(cu),zl=Xu(function(n){var t=n.length,r=t>1?n[t-1]:B;return r="function"==typeof r?(n.pop(),r):B,lu(n,r)}),ql=Xu(function(n){n=Cr(n);var t=n.length,r=t?n[0]:0,e=this.__wrapped__,i=function(t){return or(t,n)};return!(t>1||this.__actions__.length)&&e instanceof At&&O(r)?(e=e.slice(r,+r+(t?1:0)),e.__actions__.push({func:pu,args:[i],thisArg:B}),new Ct(e,this.__chain__).thru(function(n){return t&&!n.length&&n.push(B),n})):this.thru(i)}),Il=$e(function(n,t,r){Cc.call(n,r)?++n[r]:n[r]=1}),Pl=$e(function(n,t,r){Cc.call(n,r)?n[r].push(t):n[r]=[t]}),Ul=Xu(function(n,t,e){var i=-1,u="function"==typeof t,o=li(t),a=co(n)?Array(n.length):[];return fl(n,function(n){var c=u?t:o&&null!=n?n[t]:B;a[++i]=c?r(c,n,e):zr(n,t,e)}),a}),Fl=$e(function(n,t,r){n[r]=t}),Hl=$e(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Wl=Xu(function(n,t){if(null==n)return[];var r=t.length;return r>1&&ci(n,t[0],t[1])?t=[]:r>2&&ci(t[0],t[1],t[2])&&(t.length=1),Xr(n,Cr(t),[])}),Bl=yc.now,Yl=Xu(function(n,t,r){var e=Z;if(r.length){var i=I(r,Yl.placeholder);e|=Q}return Ze(n,e,t,r,i)}),Zl=Xu(function(n,t,r){var e=Z|V;if(r.length){var i=I(r,Zl.placeholder);e|=Q}return Ze(t,e,n,r,i)}),Vl=Xu(function(n,t){return mr(n,1,t)}),Xl=Xu(function(n,t,r){return mr(n,Ho(t)||0,r)}),Kl=Xu(function(n,t){t=f(Cr(t),Qe());var e=t.length;return Xu(function(i){for(var u=-1,o=Vc(i.length,e);++u<o;)i[u]=t[u].call(this,i[u]);return r(n,this,i)})}),Jl=Xu(function(n,t){var r=I(t,Jl.placeholder);return Ze(n,Q,B,t,r)}),Ql=Xu(function(n,t){var r=I(t,Ql.placeholder);return Ze(n,G,B,t,r)}),Gl=Xu(function(n,t){return Ze(n,tn,B,B,B,Cr(t))}),nf=Array.isArray,tf=je(function(n,t){Se(t,oa(t),n)}),rf=je(function(n,t){Se(t,aa(t),n)}),ef=je(function(n,t,r,e){Ee(t,aa(t),n,e)}),uf=je(function(n,t,r,e){Ee(t,oa(t),n,e)}),of=Xu(function(n,t){return or(n,Cr(t))}),af=Xu(function(n){return n.push(B,tr),r(ef,B,n)}),cf=Xu(function(n){return n.push(B,gi),r(sf,B,n)}),lf=Xu(zr),ff=je(function(n,t,r){Zr(n,t,r)}),sf=je(function(n,t,r,e){Zr(n,t,r,e)}),hf=Xu(function(n,t){return null==n?{}:(t=f(Cr(t),String),Kr(n,_r(aa(n),t)))}),pf=Xu(function(n,t){return null==n?{}:Kr(n,Cr(t))}),vf=Oe(function(n,t,r){return t=t.toLowerCase(),n+(r?ka(t):t)}),gf=Oe(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),df=Oe(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),yf=Re("toLowerCase"),mf=Re("toUpperCase"),_f=Oe(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),xf=Oe(function(n,t,r){return n+(r?" ":"")+ka(t)}),Mf=Oe(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),bf=Xu(function(n,t){try{return r(n,B,t)}catch(e){return yo(e)?e:new mc(e)}}),wf=Xu(function(n,t){return i(Cr(t),function(t){n[t]=Yl(n[t],n)}),n}),kf=Ie(),Cf=Ie(!0),Af=Xu(function(n,t){return function(r){return zr(r,n,t)}}),Sf=Xu(function(n,t){return function(r){return zr(n,r,t)}}),Ef=Ue(f),Nf=Ue(o),$f=Ue(v),jf=We(),Df=We(!0),Tf=Ye("ceil"),Lf=Ye("floor"),Rf=Ye("round");return qn.prototype=Mt.prototype,Ct.prototype=ll(Mt.prototype),Ct.prototype.constructor=Ct,At.prototype=ll(Mt.prototype),At.prototype.constructor=At,$t.prototype=tl?tl(null):wc,Rt.prototype.clear=Ot,Rt.prototype["delete"]=zt,Rt.prototype.get=qt,Rt.prototype.has=It,Rt.prototype.set=Pt,Ut.prototype.push=Ht,Wt.prototype.clear=Bt,Wt.prototype["delete"]=Yt,Wt.prototype.get=Zt,Wt.prototype.has=Vt,Wt.prototype.set=Xt,Yu.Cache=Rt,qn.after=Iu,qn.ary=Pu,qn.assign=tf,qn.assignIn=rf,qn.assignInWith=ef,qn.assignWith=uf,qn.at=of,qn.before=Uu,qn.bind=Yl,qn.bindAll=wf,qn.bindKey=Zl,qn.chain=su,qn.chunk=bi,qn.compact=wi,qn.concat=xl,qn.cond=Ya,qn.conforms=Za,qn.constant=Va,qn.countBy=Il,qn.create=Zo,qn.curry=Fu,qn.curryRight=Hu,qn.debounce=Wu,qn.defaults=af,qn.defaultsDeep=cf,qn.defer=Vl,qn.delay=Xl,qn.difference=Ml,qn.differenceBy=bl,qn.differenceWith=wl,qn.drop=ki,qn.dropRight=Ci,qn.dropRightWhile=Ai,qn.dropWhile=Si,qn.fill=Ei,qn.filter=wu,qn.flatMap=ji,qn.flatten=Di,qn.flattenDeep=Ti,qn.flip=Bu,qn.flow=kf,qn.flowRight=Cf,qn.fromPairs=Li,qn.functions=na,qn.functionsIn=ta,qn.groupBy=Pl,qn.initial=zi,qn.intersection=kl,qn.intersectionBy=Cl,qn.intersectionWith=Al,qn.invert=ua,qn.invokeMap=Ul,qn.iteratee=Ka,qn.keyBy=Fl,qn.keys=oa,qn.keysIn=aa,qn.map=Nu,qn.mapKeys=ca,qn.mapValues=la,qn.matches=Ja,qn.matchesProperty=Qa,qn.memoize=Yu,qn.merge=ff,qn.mergeWith=sf,qn.method=Af,qn.methodOf=Sf,qn.mixin=Ga,qn.negate=Zu,qn.nthArg=rc,qn.omit=hf,qn.omitBy=fa,qn.once=Vu,qn.orderBy=$u,qn.over=Ef,qn.overArgs=Kl,qn.overEvery=Nf,qn.overSome=$f,qn.partial=Jl,qn.partialRight=Ql,qn.partition=Hl,qn.pick=pf,qn.pickBy=sa,qn.property=ec,qn.propertyOf=ic,qn.pull=Sl,qn.pullAll=Ui,qn.pullAllBy=Fi,qn.pullAt=El,qn.range=jf,qn.rangeRight=Df,qn.rearg=Gl,qn.reject=Tu,qn.remove=Hi,qn.rest=Xu,qn.reverse=Wi,qn.sampleSize=Ru,qn.set=pa,qn.setWith=va,qn.shuffle=Ou,qn.slice=Bi,qn.sortBy=Wl,qn.sortedUniq=Qi,qn.sortedUniqBy=Gi,qn.split=Ra,qn.spread=Ku,qn.tail=nu,qn.take=tu,qn.takeRight=ru,qn.takeRightWhile=eu,qn.takeWhile=iu,qn.tap=hu,qn.throttle=Ju,qn.thru=pu,qn.toArray=Po,qn.toPairs=ga,qn.toPairsIn=da,qn.toPath=oc,qn.toPlainObject=Wo,qn.transform=ya,qn.unary=Qu,qn.union=Nl,qn.unionBy=$l,qn.unionWith=jl,qn.uniq=uu,qn.uniqBy=ou,qn.uniqWith=au,qn.unset=ma,qn.unzip=cu,qn.unzipWith=lu,qn.values=_a,qn.valuesIn=xa,qn.without=Dl,qn.words=Ba,qn.wrap=Gu,qn.xor=Tl,qn.xorBy=Ll,qn.xorWith=Rl,qn.zip=Ol,qn.zipObject=fu,qn.zipWith=zl,qn.extend=rf,qn.extendWith=ef,Ga(qn,qn),qn.add=cc,qn.attempt=bf,qn.camelCase=vf,qn.capitalize=ka,qn.ceil=Tf,qn.clamp=Ma,qn.clone=no,qn.cloneDeep=ro,qn.cloneDeepWith=eo,qn.cloneWith=to,qn.deburr=Ca,qn.endsWith=Aa,qn.eq=io,qn.escape=Sa,qn.escapeRegExp=Ea,qn.every=bu,qn.find=ku,qn.findIndex=Ni,qn.findKey=Vo,qn.findLast=Cu,qn.findLastIndex=$i,qn.findLastKey=Xo,qn.floor=Lf,qn.forEach=Au,qn.forEachRight=Su,qn.forIn=Ko,qn.forInRight=Jo,qn.forOwn=Qo,qn.forOwnRight=Go,qn.get=ra,qn.gt=uo,qn.gte=oo,qn.has=ea,qn.hasIn=ia,qn.head=Ri,qn.identity=Xa,qn.includes=Eu,qn.indexOf=Oi,qn.inRange=ba,qn.invoke=lf,qn.isArguments=ao,qn.isArray=nf,qn.isArrayLike=co,qn.isArrayLikeObject=lo,qn.isBoolean=fo,qn.isDate=so,qn.isElement=ho,qn.isEmpty=po,qn.isEqual=vo,qn.isEqualWith=go,qn.isError=yo,qn.isFinite=mo,qn.isFunction=_o,qn.isInteger=xo,qn.isLength=Mo,qn.isMatch=ko,qn.isMatchWith=Co,qn.isNaN=Ao,qn.isNative=So,qn.isNil=No,qn.isNull=Eo,qn.isNumber=$o,qn.isObject=bo,qn.isObjectLike=wo,qn.isPlainObject=jo,qn.isRegExp=Do,qn.isSafeInteger=To,qn.isString=Lo,qn.isSymbol=Ro,qn.isTypedArray=Oo,qn.isUndefined=zo,qn.join=qi,qn.kebabCase=gf,qn.last=Ii,qn.lastIndexOf=Pi,qn.lowerCase=df,qn.lowerFirst=yf,qn.lt=qo,qn.lte=Io,qn.max=lc,qn.maxBy=fc,qn.mean=sc,qn.min=hc,qn.minBy=pc,qn.noConflict=nc,qn.noop=tc,qn.now=Bl,qn.pad=Na,qn.padEnd=$a,qn.padStart=ja,qn.parseInt=Da,qn.random=wa,qn.reduce=ju,qn.reduceRight=Du,qn.repeat=Ta,qn.replace=La,qn.result=ha,qn.round=Rf,qn.runInContext=W,qn.sample=Lu,qn.size=zu,qn.snakeCase=_f,qn.some=qu,qn.sortedIndex=Yi,qn.sortedIndexBy=Zi,qn.sortedIndexOf=Vi,qn.sortedLastIndex=Xi,qn.sortedLastIndexBy=Ki,qn.sortedLastIndexOf=Ji,qn.startCase=xf,qn.startsWith=Oa,qn.subtract=vc,qn.sum=gc,qn.sumBy=dc,qn.template=za,qn.times=uc,qn.toInteger=Uo,qn.toLength=Fo,qn.toLower=qa,qn.toNumber=Ho,qn.toSafeInteger=Bo,qn.toString=Yo,qn.toUpper=Ia,qn.trim=Pa,qn.trimEnd=Ua,qn.trimStart=Fa,qn.truncate=Ha,qn.unescape=Wa,qn.uniqueId=ac,qn.upperCase=Mf,qn.upperFirst=mf,qn.each=Au,qn.eachRight=Su,qn.first=Ri,Ga(qn,function(){var n={};return Sr(qn,function(t,r){Cc.call(qn.prototype,r)||(n[r]=t)}),n}(),{chain:!1}),qn.VERSION=Y,i(["bind","bindKey","curry","curryRight","partial","partialRight"],function(n){qn[n].placeholder=qn}),i(["drop","take"],function(n,t){At.prototype[n]=function(r){var e=this.__filtered__;if(e&&!t)return new At(this);r=r===B?1:Zc(Uo(r),0);var i=this.clone();return e?i.__takeCount__=Vc(r,i.__takeCount__):i.__views__.push({size:Vc(r,xn),type:n+(i.__dir__<0?"Right":"")}),i},At.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),i(["filter","map","takeWhile"],function(n,t){var r=t+1,e=r==sn||r==pn;At.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qe(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),i(["head","last"],function(n,t){var r="take"+(t?"Right":"");At.prototype[n]=function(){return this[r](1).value()[0]}}),i(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");At.prototype[n]=function(){return this.__filtered__?new At(this):this[r](1)}}),At.prototype.compact=function(){return this.filter(Xa)},At.prototype.find=function(n){return this.filter(n).head()},At.prototype.findLast=function(n){return this.reverse().find(n)},At.prototype.invokeMap=Xu(function(n,t){return"function"==typeof n?new At(this):this.map(function(r){return zr(r,n,t)})}),At.prototype.reject=function(n){return n=Qe(n,3),this.filter(function(t){return!n(t)})},At.prototype.slice=function(n,t){n=Uo(n);var r=this;return r.__filtered__&&(n>0||0>t)?new At(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==B&&(t=Uo(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},At.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},At.prototype.toArray=function(){return this.take(xn)},Sr(At.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),i=qn[e?"take"+("last"==t?"Right":""):t],u=e||/^find/.test(t);i&&(qn.prototype[t]=function(){var t=this.__wrapped__,o=e?[1]:arguments,a=t instanceof At,c=o[0],l=a||nf(t),f=function(n){var t=i.apply(qn,s([n],o));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=u&&!h,g=a&&!p;if(!u&&l){t=g?t:new At(this);var d=n.apply(t,o);return d.__actions__.push({func:pu,args:[f],thisArg:B}),new Ct(d,h)}return v&&g?n.apply(this,o):(d=this.thru(f),v?e?d.value()[0]:d.value():d)})}),i(["pop","push","shift","sort","splice","unshift"],function(n){var t=bc[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);qn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),Sr(At.prototype,function(n,t){var r=qn[t];if(r){var e=r.name+"",i=cl[e]||(cl[e]=[]);i.push({name:t,func:r})}}),cl[Pe(B,V).name]=[{name:"wrapper",func:B}],At.prototype.clone=St,At.prototype.reverse=Et,At.prototype.value=Nt,qn.prototype.at=ql,qn.prototype.chain=vu,qn.prototype.commit=gu,qn.prototype.flatMap=du,qn.prototype.next=yu,qn.prototype.plant=_u,qn.prototype.reverse=xu,qn.prototype.toJSON=qn.prototype.valueOf=qn.prototype.value=Mu,qc&&(qn.prototype[qc]=mu),qn}var B,Y="4.0.1",Z=1,V=2,X=4,K=8,J=16,Q=32,G=64,nn=128,tn=256,rn=512,en=1,un=2,on=30,an="...",cn=150,ln=16,fn=200,sn=1,hn=2,pn=3,vn="Expected a function",gn="__lodash_hash_undefined__",dn=1/0,yn=9007199254740991,mn=1.7976931348623157e308,_n=NaN,xn=4294967295,Mn=xn-1,bn=xn>>>1,wn="__lodash_placeholder__",kn="[object Arguments]",Cn="[object Array]",An="[object Boolean]",Sn="[object Date]",En="[object Error]",Nn="[object Function]",$n="[object GeneratorFunction]",jn="[object Map]",Dn="[object Number]",Tn="[object Object]",Ln="[object RegExp]",Rn="[object Set]",On="[object String]",zn="[object Symbol]",qn="[object WeakMap]",In="[object ArrayBuffer]",Pn="[object Float32Array]",Un="[object Float64Array]",Fn="[object Int8Array]",Hn="[object Int16Array]",Wn="[object Int32Array]",Bn="[object Uint8Array]",Yn="[object Uint8ClampedArray]",Zn="[object Uint16Array]",Vn="[object Uint32Array]",Xn=/\b__p \+= '';/g,Kn=/\b(__p \+=) '' \+/g,Jn=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Qn=/&(?:amp|lt|gt|quot|#39|#96);/g,Gn=/[&<>"'`]/g,nt=RegExp(Qn.source),tt=RegExp(Gn.source),rt=/<%-([\s\S]+?)%>/g,et=/<%([\s\S]+?)%>/g,it=/<%=([\s\S]+?)%>/g,ut=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,ot=/^\w*$/,at=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g,ct=/[\\^$.*+?()[\]{}|]/g,lt=RegExp(ct.source),ft=/^\s+|\s+$/g,st=/^\s+/,ht=/\s+$/,pt=/\\(\\)?/g,vt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,gt=/\w*$/,dt=/^0x/i,yt=/^[-+]0x[0-9a-f]+$/i,mt=/^0b[01]+$/i,_t=/^\[object .+?Constructor\]$/,xt=/^0o[0-7]+$/i,Mt=/^(?:0|[1-9]\d*)$/,bt=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,wt=/($^)/,kt=/['\n\r\u2028\u2029\\]/g,Ct="\\ud800-\\udfff",At="\\u0300-\\u036f\\ufe20-\\ufe23",St="\\u20d0-\\u20f0",Et="\\u2700-\\u27bf",Nt="a-z\\xdf-\\xf6\\xf8-\\xff",$t="\\xac\\xb1\\xd7\\xf7",jt="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Dt="\\u2018\\u2019\\u201c\\u201d",Tt=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Lt="A-Z\\xc0-\\xd6\\xd8-\\xde",Rt="\\ufe0e\\ufe0f",Ot=$t+jt+Dt+Tt,zt="["+Ct+"]",qt="["+Ot+"]",It="["+At+St+"]",Pt="\\d+",Ut="["+Et+"]",Ft="["+Nt+"]",Ht="[^"+Ct+Ot+Pt+Et+Nt+Lt+"]",Wt="\\ud83c[\\udffb-\\udfff]",Bt="(?:"+It+"|"+Wt+")",Yt="[^"+Ct+"]",Zt="(?:\\ud83c[\\udde6-\\uddff]){2}",Vt="[\\ud800-\\udbff][\\udc00-\\udfff]",Xt="["+Lt+"]",Kt="\\u200d",Jt="(?:"+Ft+"|"+Ht+")",Qt="(?:"+Xt+"|"+Ht+")",Gt=Bt+"?",nr="["+Rt+"]?",tr="(?:"+Kt+"(?:"+[Yt,Zt,Vt].join("|")+")"+nr+Gt+")*",rr=nr+Gt+tr,er="(?:"+[Ut,Zt,Vt].join("|")+")"+rr,ir="(?:"+[Yt+It+"?",It,Zt,Vt,zt].join("|")+")",ur=RegExp(It,"g"),or=RegExp(Wt+"(?="+Wt+")|"+ir+rr,"g"),ar=RegExp("["+Kt+Ct+At+St+Rt+"]"),cr=/[a-zA-Z0-9]+/g,lr=RegExp([Xt+"?"+Ft+"+(?="+[qt,Xt,"$"].join("|")+")",Qt+"+(?="+[qt,Xt+Jt,"$"].join("|")+")",Xt+"?"+Jt+"+",Xt+"+",Pt,er].join("|"),"g"),fr=/[a-z][A-Z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,sr=["Array","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Reflect","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],hr=-1,pr={};pr[Pn]=pr[Un]=pr[Fn]=pr[Hn]=pr[Wn]=pr[Bn]=pr[Yn]=pr[Zn]=pr[Vn]=!0,pr[kn]=pr[Cn]=pr[In]=pr[An]=pr[Sn]=pr[En]=pr[Nn]=pr[jn]=pr[Dn]=pr[Tn]=pr[Ln]=pr[Rn]=pr[On]=pr[qn]=!1;var vr={};vr[kn]=vr[Cn]=vr[In]=vr[An]=vr[Sn]=vr[Pn]=vr[Un]=vr[Fn]=vr[Hn]=vr[Wn]=vr[jn]=vr[Dn]=vr[Tn]=vr[Ln]=vr[Rn]=vr[On]=vr[zn]=vr[Bn]=vr[Yn]=vr[Zn]=vr[Vn]=!0,vr[En]=vr[Nn]=vr[qn]=!1;var gr={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss"},dr={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","`":"&#96;"},yr={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#96;":"`"},mr={"function":!0,object:!0},_r={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},xr=parseFloat,Mr=parseInt,br=mr[typeof exports]&&exports&&!exports.nodeType?exports:null,wr=mr[typeof module]&&module&&!module.nodeType?module:null,kr=E(br&&wr&&"object"==typeof global&&global),Cr=E(mr[typeof self]&&self),Ar=E(mr[typeof window]&&window),Sr=wr&&wr.exports===br?br:null,Er=E(mr[typeof this]&&this),Nr=kr||Ar!==(Er&&Er.window)&&Ar||Cr||Er||Function("return this")(),$r=W();(Ar||Cr||{})._=$r,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return $r}):br&&wr?(Sr&&((wr.exports=$r)._=$r),br._=$r):Nr._=$r}.call(this),function(n,t,r){"use strict";function e(n,t,r){if(!n)throw dn("areq","Argument '{0}' is {1}",t||"?",r||"required");return n}function i(n,t){return n||t?n?t?(H(n)&&(n=n.join(" ")),H(t)&&(t=t.join(" ")),n+" "+t):n:t:""}function u(n){var t={};return n&&(n.to||n.from)&&(t.to=n.to,t.from=n.from),t}function o(n,t,r){var e="";return n=H(n)?n:n&&W(n)&&n.length?n.split(/\s+/):[],F(n,function(n,i){n&&n.length>0&&(e+=i>0?" ":"",e+=r?t+n:n+t)}),e}function a(n,t){var r=n.indexOf(t);t>=0&&n.splice(r,1)}function c(n){if(n instanceof U)switch(n.length){case 0:return[];case 1:if(n[0].nodeType===K)return n;break;default:return U(l(n))}return n.nodeType===K?U(n):void 0}function l(n){if(!n[0])return n;for(var t=0;t<n.length;t++){var r=n[t];if(r.nodeType==K)return r}}function f(n,t,r){F(t,function(t){n.addClass(t,r)})}function s(n,t,r){F(t,function(t){n.removeClass(t,r)})}function h(n){return function(t,r){r.addClass&&(f(n,t,r.addClass),r.addClass=null),r.removeClass&&(s(n,t,r.removeClass),r.removeClass=null)}}function p(n){if(n=n||{},!n.$$prepared){var t=n.domOperation||q;n.domOperation=function(){n.$$domOperationFired=!0,t(),t=q},n.$$prepared=!0}return n}function v(n,t){g(n,t),d(n,t)}function g(n,t){t.from&&(n.css(t.from),t.from=null)}function d(n,t){t.to&&(n.css(t.to),t.to=null)}function y(n,t,r){var e=(t.addClass||"")+" "+(r.addClass||""),i=(t.removeClass||"")+" "+(r.removeClass||""),u=m(n.attr("class"),e,i);r.preparationClasses&&(t.preparationClasses=C(r.preparationClasses,t.preparationClasses),delete r.preparationClasses);var o=t.domOperation!==q?t.domOperation:null;return P(t,r),o&&(t.domOperation=o),u.addClass?t.addClass=u.addClass:t.addClass=null,u.removeClass?t.removeClass=u.removeClass:t.removeClass=null,t}function m(n,t,r){function e(n){W(n)&&(n=n.split(" "));var t={};return F(n,function(n){n.length&&(t[n]=!0)}),t}var i=1,u=-1,o={};n=e(n),t=e(t),F(t,function(n,t){o[t]=i}),r=e(r),F(r,function(n,t){o[t]=o[t]===i?null:u});var a={addClass:"",removeClass:""};return F(o,function(t,r){var e,o;t===i?(e="addClass",o=!n[r]):t===u&&(e="removeClass",o=n[r]),o&&(a[e].length&&(a[e]+=" "),a[e]+=r)}),a}function _(n){return n instanceof t.element?n[0]:n}function x(n,t,r){var e="";t&&(e=o(t,G,!0)),r.addClass&&(e=C(e,o(r.addClass,J))),r.removeClass&&(e=C(e,o(r.removeClass,Q))),e.length&&(r.preparationClasses=e,n.addClass(e))}function M(n,t){t.preparationClasses&&(n.removeClass(t.preparationClasses),t.preparationClasses=null),t.activeClasses&&(n.removeClass(t.activeClasses),t.activeClasses=null)}function b(n,t){var r=t?"-"+t+"s":"";return k(n,[vn,r]),[vn,r]}function w(n,t){var r=t?"paused":"",e=O+fn;return k(n,[e,r]),[e,r]}function k(n,t){var r=t[0],e=t[1];n.style[r]=e}function C(n,t){return n?t?n+" "+t:n:t}function A(n){return[pn,n+"s"]}function S(n,t){var r=t?hn:vn;return[r,n+"s"]}function E(n,t,r){var e=Object.create(null),i=n.getComputedStyle(t)||{};return F(r,function(n,t){var r=i[n];if(r){var u=r.charAt(0);("-"===u||"+"===u||u>=0)&&(r=N(r)),0===r&&(r=null),e[t]=r}}),e}function N(n){var t=0,r=n.split(/\s*,\s*/);return F(r,function(n){"s"==n.charAt(n.length-1)&&(n=n.substring(0,n.length-1)),n=parseFloat(n)||0,t=t?Math.max(n,t):n}),t}function $(n){return 0===n||null!=n}function j(n,t){var r=L,e=n+"s";return t?r+=un:e+=" linear all",[r,e]}function D(){var n=Object.create(null);return{flush:function(){n=Object.create(null)},count:function(t){var r=n[t];return r?r.total:0},get:function(t){var r=n[t];return r&&r.value},put:function(t,r){n[t]?n[t].total++:n[t]={total:1,value:r}}}}function T(n,t,r){F(r,function(r){n[r]=Z(n[r])?n[r]:t.style.getPropertyValue(r)})}var L,R,O,z,q=t.noop,I=t.copy,P=t.extend,U=t.element,F=t.forEach,H=t.isArray,W=t.isString,B=t.isObject,Y=t.isUndefined,Z=t.isDefined,V=t.isFunction,X=t.isElement,K=1,J="-add",Q="-remove",G="ng-",nn="-active",tn="ng-animate",rn="$$ngAnimateChildren",en="";Y(n.ontransitionend)&&Z(n.onwebkittransitionend)?(en="-webkit-",L="WebkitTransition",R="webkitTransitionEnd transitionend"):(L="transition",R="transitionend"),Y(n.onanimationend)&&Z(n.onwebkitanimationend)?(en="-webkit-",O="WebkitAnimation",z="webkitAnimationEnd animationend"):(O="animation",z="animationend");var un="Duration",on="Property",an="Delay",cn="TimingFunction",ln="IterationCount",fn="PlayState",sn=9999,hn=O+an,pn=O+un,vn=L+an,gn=L+un,dn=t.$$minErr("ng"),yn=["$$rAF",function(n){function t(n){e=e.concat(n),r()}function r(){if(e.length){for(var t=e.shift(),u=0;u<t.length;u++)t[u]();i||n(function(){i||r()})}}var e,i;return e=t.queue=[],t.waitUntilQuiet=function(t){i&&i(),i=n(function(){i=null,t(),r()})},t}],mn=[function(){return function(n,r,e){var i=e.ngAnimateChildren;t.isString(i)&&0===i.length?r.data(rn,!0):e.$observe("ngAnimateChildren",function(n){n="on"===n||"true"===n,r.data(rn,n)})}}],_n="$$animateCss",xn=1e3,Mn=3,bn=1.5,wn={transitionDuration:gn,transitionDelay:vn,transitionProperty:L+on,animationDuration:pn,animationDelay:hn,animationIterationCount:O+ln},kn={transitionDuration:gn,transitionDelay:vn,animationDuration:pn,animationDelay:hn},Cn=["$animateProvider",function(n){var t=D(),r=D();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$$forceReflow","$sniffer","$$rAFScheduler","$$animateQueue",function(n,e,i,c,l,f,s,y){function m(n,t){var r="$$ngAnimateParentKey",e=n.parentNode,i=e[r]||(e[r]=++P);return i+"-"+n.getAttribute("class")+"-"+t}function x(r,e,i,u){var o=t.get(i);return o||(o=E(n,r,u),"infinite"===o.animationIterationCount&&(o.animationIterationCount=1)),t.put(i,o),o}function M(i,u,a,c){var l;if(t.count(a)>0&&(l=r.get(a),!l)){var f=o(u,"-stagger");e.addClass(i,f),l=E(n,i,c),l.animationDuration=Math.max(l.animationDuration,0),l.transitionDuration=Math.max(l.transitionDuration,0),e.removeClass(i,f),r.put(a,l)}return l||{}}function C(n){U.push(n),s.waitUntilQuiet(function(){t.flush(),r.flush();for(var n=l(),e=0;e<U.length;e++)U[e](n);U.length=0})}function N(n,t,r){var e=x(n,t,r,wn),i=e.animationDelay,u=e.transitionDelay;return e.maxDelay=i&&u?Math.max(i,u):i||u,e.maxDuration=Math.max(e.animationDuration*e.animationIterationCount,e.transitionDuration),e}var D=h(e),P=0,U=[];return function(n,r){function l(){h()}function s(){h(!0)}function h(t){Z||X&&V||(Z=!0,V=!1,W.$$skipPreparationClasses||e.removeClass(n,wn),e.removeClass(n,An),w(Y,!1),b(Y,!1),F(fn,function(n){Y.style[n[0]]=""}),D(n,W),v(n,W),Object.keys(B).length&&F(B,function(n,t){n?Y.style.setProperty(t,n):Y.style.removeProperty(t)}),W.onDone&&W.onDone(),vn&&vn.length&&n.off(vn.join(" "),P),K&&K.complete(!t))}function x(n){Pn.blockTransition&&b(Y,n),Pn.blockKeyframeAnimation&&w(Y,!!n)}function E(){return K=new i({end:l,cancel:s}),C(q),h(),{$$willAnimate:!1,start:function(){return K},end:l}}function P(n){n.stopPropagation();var t=n.originalEvent||n,r=t.$manualTimeStamp||Date.now(),e=parseFloat(t.elapsedTime.toFixed(Mn));Math.max(r-ln,0)>=en&&e>=un&&(X=!0,h())}function U(){function t(){if(!Z){if(x(!1),F(fn,function(n){var t=n[0],r=n[1];Y.style[t]=r}),D(n,W),e.addClass(n,An),Pn.recalculateTimingStyles){if(Cn=Y.className+" "+wn,Nn=m(Y,Cn),qn=N(Y,Cn,Nn),In=qn.maxDelay,rn=Math.max(In,0),un=qn.maxDuration,0===un)return void h();Pn.hasTransitions=qn.transitionDuration>0,Pn.hasAnimations=qn.animationDuration>0}if(Pn.applyAnimationDelay&&(In="boolean"!=typeof W.delay&&$(W.delay)?parseFloat(W.delay):In,rn=Math.max(In,0),qn.animationDelay=In,Un=S(In,!0),fn.push(Un),Y.style[Un[0]]=Un[1]),en=rn*xn,an=un*xn,W.easing){var t,i=W.easing;Pn.hasTransitions&&(t=L+cn,fn.push([t,i]),Y.style[t]=i),Pn.hasAnimations&&(t=O+cn,fn.push([t,i]),Y.style[t]=i)}qn.transitionDuration&&vn.push(R),qn.animationDuration&&vn.push(z),ln=Date.now();var u=en+bn*an,o=ln+u,a=n.data(_n)||[],l=!0;if(a.length){var f=a[0];l=o>f.expectedEndTime,l?c.cancel(f.timer):a.push(h)}if(l){var s=c(r,u,!1);a[0]={timer:s,expectedEndTime:o},a.push(h),n.data(_n,a)}vn.length&&n.on(vn.join(" "),P),W.to&&(W.cleanupStyles&&T(B,Y,Object.keys(W.to)),d(n,W))}}function r(){var t=n.data(_n);if(t){for(var r=1;r<t.length;r++)t[r]();n.removeData(_n)}}if(!Z){if(!Y.parentNode)return void h();var i=function(n){if(X)V&&n&&(V=!1,h());else if(V=!n,qn.animationDuration){var t=w(Y,V);V?fn.push(t):a(fn,t)}},u=On>0&&(qn.transitionDuration&&0===$n.transitionDuration||qn.animationDuration&&0===$n.animationDuration)&&Math.max($n.animationDelay,$n.transitionDelay);u?c(t,Math.floor(u*On*xn),!1):t(),tn.resume=function(){i(!0)},tn.pause=function(){i(!1)}}}var W=r||{};W.$$prepared||(W=p(I(W)));var B={},Y=_(n);if(!Y||!Y.parentNode||!y.enabled())return E();var Z,V,X,K,tn,rn,en,un,an,ln,fn=[],hn=n.attr("class"),pn=u(W),vn=[];if(0===W.duration||!f.animations&&!f.transitions)return E();var gn=W.event&&H(W.event)?W.event.join(" "):W.event,dn=gn&&W.structural,yn="",mn="";dn?yn=o(gn,G,!0):gn&&(yn=gn),W.addClass&&(mn+=o(W.addClass,J)),W.removeClass&&(mn.length&&(mn+=" "),mn+=o(W.removeClass,Q)),W.applyClassesEarly&&mn.length&&D(n,W);var wn=[yn,mn].join(" ").trim(),Cn=hn+" "+wn,An=o(wn,nn),Sn=pn.to&&Object.keys(pn.to).length>0,En=(W.keyframeStyle||"").length>0;if(!En&&!Sn&&!wn)return E();var Nn,$n;if(W.stagger>0){var jn=parseFloat(W.stagger);$n={transitionDelay:jn,animationDelay:jn,transitionDuration:0,animationDuration:0}}else Nn=m(Y,Cn),$n=M(Y,wn,Nn,kn);W.$$skipPreparationClasses||e.addClass(n,wn);var Dn;if(W.transitionStyle){var Tn=[L,W.transitionStyle];k(Y,Tn),fn.push(Tn)}if(W.duration>=0){Dn=Y.style[L].length>0;var Ln=j(W.duration,Dn);k(Y,Ln),fn.push(Ln)}if(W.keyframeStyle){var Rn=[O,W.keyframeStyle];k(Y,Rn),fn.push(Rn)}var On=$n?W.staggerIndex>=0?W.staggerIndex:t.count(Nn):0,zn=0===On;zn&&!W.skipBlocking&&b(Y,sn);var qn=N(Y,Cn,Nn),In=qn.maxDelay;rn=Math.max(In,0),un=qn.maxDuration;var Pn={};if(Pn.hasTransitions=qn.transitionDuration>0,Pn.hasAnimations=qn.animationDuration>0,Pn.hasTransitionAll=Pn.hasTransitions&&"all"==qn.transitionProperty,Pn.applyTransitionDuration=Sn&&(Pn.hasTransitions&&!Pn.hasTransitionAll||Pn.hasAnimations&&!Pn.hasTransitions),Pn.applyAnimationDuration=W.duration&&Pn.hasAnimations,Pn.applyTransitionDelay=$(W.delay)&&(Pn.applyTransitionDuration||Pn.hasTransitions),Pn.applyAnimationDelay=$(W.delay)&&Pn.hasAnimations,Pn.recalculateTimingStyles=mn.length>0,(Pn.applyTransitionDuration||Pn.applyAnimationDuration)&&(un=W.duration?parseFloat(W.duration):un,Pn.applyTransitionDuration&&(Pn.hasTransitions=!0,qn.transitionDuration=un,Dn=Y.style[L+on].length>0,fn.push(j(un,Dn))),Pn.applyAnimationDuration&&(Pn.hasAnimations=!0,qn.animationDuration=un,fn.push(A(un)))),0===un&&!Pn.recalculateTimingStyles)return E();if(null!=W.delay){var Un;"boolean"!=typeof W.delay&&(Un=parseFloat(W.delay),rn=Math.max(Un,0)),Pn.applyTransitionDelay&&fn.push(S(Un)),Pn.applyAnimationDelay&&fn.push(S(Un,!0))}return null==W.duration&&qn.transitionDuration>0&&(Pn.recalculateTimingStyles=Pn.recalculateTimingStyles||zn),en=rn*xn,an=un*xn,W.skipBlocking||(Pn.blockTransition=qn.transitionDuration>0,Pn.blockKeyframeAnimation=qn.animationDuration>0&&$n.animationDelay>0&&0===$n.animationDuration),W.from&&(W.cleanupStyles&&T(B,Y,Object.keys(W.from)),g(n,W)),Pn.blockTransition||Pn.blockKeyframeAnimation?x(un):W.skipBlocking||b(Y,!1),{$$willAnimate:!0,end:l,start:function(){return Z?void 0:(tn={end:l,cancel:s,resume:null,pause:null},K=new i(tn),C(U),K)}}}}]}],An=["$$animationProvider",function(n){function t(n){return n.parentNode&&11===n.parentNode.nodeType}n.drivers.push("$$animateCssDriver");var r="ng-animate-shim",e="ng-anchor",i="ng-anchor-out",u="ng-anchor-in";this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$sniffer","$$jqLite","$document",function(n,o,a,c,l,f,s){function p(n){return n.replace(/\bng-\S+\b/g,"");
+}function v(n,t){return W(n)&&(n=n.split(" ")),W(t)&&(t=t.split(" ")),n.filter(function(n){return-1===t.indexOf(n)}).join(" ")}function g(t,o,c){function l(n){var t={},r=_(n).getBoundingClientRect();return F(["width","height","top","left"],function(n){var e=r[n];switch(n){case"top":e+=m.scrollTop;break;case"left":e+=m.scrollLeft}t[n]=Math.floor(e)+"px"}),t}function f(){var t=n(d,{addClass:i,delay:!0,from:l(o)});return t.$$willAnimate?t:null}function s(n){return n.attr("class")||""}function h(){var t=p(s(c)),r=v(t,y),e=v(y,t),o=n(d,{to:l(c),addClass:u+" "+r,removeClass:i+" "+e,delay:!0});return o.$$willAnimate?o:null}function g(){d.remove(),o.removeClass(r),c.removeClass(r)}var d=U(_(o).cloneNode(!0)),y=p(s(d));o.addClass(r),c.addClass(r),d.addClass(e),M.append(d);var x,b=f();if(!b&&(x=h(),!x))return g();var w=b||x;return{start:function(){function n(){r&&r.end()}var t,r=w.start();return r.done(function(){return r=null,!x&&(x=h())?(r=x.start(),r.done(function(){r=null,g(),t.complete()}),r):(g(),void t.complete())}),t=new a({end:n,cancel:n})}}}function d(n,t,r,e){var i=y(n,q),u=y(t,q),o=[];return F(e,function(n){var t=n.out,e=n["in"],i=g(r,t,e);i&&o.push(i)}),i||u||0!==o.length?{start:function(){function n(){F(t,function(n){n.end()})}var t=[];i&&t.push(i.start()),u&&t.push(u.start()),F(o,function(n){t.push(n.start())});var r=new a({end:n,cancel:n});return a.all(t,function(n){r.complete(n)}),r}}:void 0}function y(t){var r=t.element,e=t.options||{};t.structural&&(e.event=t.event,e.structural=!0,e.applyClassesEarly=!0,"leave"===t.event&&(e.onDone=e.domOperation)),e.preparationClasses&&(e.event=C(e.event,e.preparationClasses));var i=n(r,e);return i.$$willAnimate?i:null}if(!l.animations&&!l.transitions)return q;var m=s[0].body,x=_(c),M=U(t(x)||m.contains(x)?x:m);h(f);return function(n){return n.from&&n.to?d(n.from,n.to,n.classes,n.anchors):y(n)}}]}],Sn=["$animateProvider",function(n){this.$get=["$injector","$$AnimateRunner","$$jqLite",function(t,r,e){function i(r){r=H(r)?r:r.split(" ");for(var e=[],i={},u=0;u<r.length;u++){var o=r[u],a=n.$$registeredAnimations[o];a&&!i[o]&&(e.push(t.get(a)),i[o]=!0)}return e}var u=h(e);return function(n,t,e,o){function a(){o.domOperation(),u(n,o)}function c(){h=!0,a(),v(n,o)}function l(n,t,e,i,u){var o;switch(e){case"animate":o=[t,i.from,i.to,u];break;case"setClass":o=[t,y,m,u];break;case"addClass":o=[t,y,u];break;case"removeClass":o=[t,m,u];break;default:o=[t,u]}o.push(i);var a=n.apply(n,o);if(a)if(V(a.start)&&(a=a.start()),a instanceof r)a.done(u);else if(V(a))return a;return q}function f(n,t,e,i,u){var o=[];return F(i,function(i){var a=i[u];a&&o.push(function(){var i,u,o=!1,c=function(n){o||(o=!0,(u||q)(n),i.complete(!n))};return i=new r({end:function(){c()},cancel:function(){c(!0)}}),u=l(a,n,t,e,function(n){var t=n===!1;c(t)}),i})}),o}function s(n,t,e,i,u){var o=f(n,t,e,i,u);if(0===o.length){var a,c;"beforeSetClass"===u?(a=f(n,"removeClass",e,i,"beforeRemoveClass"),c=f(n,"addClass",e,i,"beforeAddClass")):"setClass"===u&&(a=f(n,"removeClass",e,i,"removeClass"),c=f(n,"addClass",e,i,"addClass")),a&&(o=o.concat(a)),c&&(o=o.concat(c))}if(0!==o.length)return function(n){var t=[];return o.length&&F(o,function(n){t.push(n())}),t.length?r.all(t,n):n(),function(n){F(t,function(t){n?t.cancel():t.end()})}}}var h=!1;3===arguments.length&&B(e)&&(o=e,e=null),o=p(o),e||(e=n.attr("class")||"",o.addClass&&(e+=" "+o.addClass),o.removeClass&&(e+=" "+o.removeClass));var g,d,y=o.addClass,m=o.removeClass,_=i(e);if(_.length){var x,M;"leave"==t?(M="leave",x="afterLeave"):(M="before"+t.charAt(0).toUpperCase()+t.substr(1),x=t),"enter"!==t&&"move"!==t&&(g=s(n,t,o,_,M)),d=s(n,t,o,_,x)}if(g||d){var b;return{$$willAnimate:!0,end:function(){return b?b.end():(c(),b=new r,b.complete(!0)),b},start:function(){function n(n){c(n),b.complete(n)}function t(t){h||((e||q)(t),n(t))}if(b)return b;b=new r;var e,i=[];return g&&i.push(function(n){e=g(n)}),i.length?i.push(function(n){a(),n(!0)}):a(),d&&i.push(function(n){e=d(n)}),b.setHost({end:function(){t()},cancel:function(){t(!0)}}),r.chain(i,n),b}}}}}]}],En=["$$animationProvider",function(n){n.drivers.push("$$animateJsDriver"),this.$get=["$$animateJs","$$AnimateRunner",function(n,t){function r(t){var r=t.element,e=t.event,i=t.options,u=t.classes;return n(r,e,u,i)}return function(n){if(n.from&&n.to){var e=r(n.from),i=r(n.to);if(!e&&!i)return;return{start:function(){function n(){return function(){F(u,function(n){n.end()})}}function r(n){o.complete(n)}var u=[];e&&u.push(e.start()),i&&u.push(i.start()),t.all(u,r);var o=new t({end:n(),cancel:n()});return o}}}return r(n)}}]}],Nn="data-ng-animate",$n="$ngAnimatePin",jn=["$animateProvider",function(n){function t(n){if(!n)return null;var t=n.split(f),r=Object.create(null);return F(t,function(n){r[n]=!0}),r}function r(n,r){if(n&&r){var e=t(r);return n.split(f).some(function(n){return e[n]})}}function i(n,t,r,e){return s[n].some(function(n){return n(t,r,e)})}function u(n,t){n=n||{};var r=(n.addClass||"").length>0,e=(n.removeClass||"").length>0;return t?r&&e:r||e}var o=1,a=2,f=" ",s=this.rules={skip:[],cancel:[],join:[]};s.join.push(function(n,t,r){return!t.structural&&u(t.options)}),s.skip.push(function(n,t,r){return!t.structural&&!u(t.options)}),s.skip.push(function(n,t,r){return"leave"==r.event&&t.structural}),s.skip.push(function(n,t,r){return r.structural&&r.state===a&&!t.structural}),s.cancel.push(function(n,t,r){return r.structural&&t.structural}),s.cancel.push(function(n,t,r){return r.state===a&&t.structural}),s.cancel.push(function(n,t,e){var i=t.options.addClass,u=t.options.removeClass,o=e.options.addClass,a=e.options.removeClass;return Y(i)&&Y(u)||Y(o)&&Y(a)?!1:r(i,a)||r(u,o)}),this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite","$$forceReflow",function(t,r,f,s,g,d,m,b,w,k){function C(){var n=!1;return function(t){n?t():r.$$postDigest(function(){n=!0,t()})}}function A(n,t){return y(n,t,{})}function S(n,t,r){var e=_(t),i=_(n),u=[],o=q[r];return o&&F(o,function(n){G.call(n.node,e)?u.push(n.callback):"leave"===r&&G.call(n.node,i)&&u.push(n.callback)}),u}function E(n,e,l){function f(r,e,i,u){E(function(){var r=S(b,n,e);r.length&&t(function(){F(r,function(t){t(n,i,u)})})}),r.progress(e,i,u)}function h(t){M(n,w),Q(n,w),v(n,w),w.domOperation(),k.complete(!t)}var g,b,w=I(l);n=c(n),n&&(g=_(n),b=n.parent()),w=p(w);var k=new m,E=C();if(H(w.addClass)&&(w.addClass=w.addClass.join(" ")),w.addClass&&!W(w.addClass)&&(w.addClass=null),H(w.removeClass)&&(w.removeClass=w.removeClass.join(" ")),w.removeClass&&!W(w.removeClass)&&(w.removeClass=null),w.from&&!B(w.from)&&(w.from=null),w.to&&!B(w.to)&&(w.to=null),!g)return h(),k;var j=[g.className,w.addClass,w.removeClass].join(" ");if(!J(j))return h(),k;var z=["enter","move","leave"].indexOf(e)>=0,q=!O||s[0].hidden||R.get(g),P=!q&&L.get(g)||{},U=!!P.state;if(q||U&&P.state==o||(q=!D(n,b,e)),q)return h(),k;z&&N(n);var Y={structural:z,element:n,event:e,close:h,options:w,runner:k};if(U){var Z=i("skip",n,Y,P);if(Z)return P.state===a?(h(),k):(y(n,P.options,w),P.runner);var V=i("cancel",n,Y,P);if(V)if(P.state===a)P.runner.end();else{if(!P.structural)return y(n,P.options,Y.options),P.runner;P.close()}else{var X=i("join",n,Y,P);if(X){if(P.state!==a)return x(n,z?e:null,w),e=Y.event=P.event,w=y(n,P.options,Y.options),P.runner;A(n,w)}}}else A(n,w);var K=Y.structural;if(K||(K="animate"===Y.event&&Object.keys(Y.options.to||{}).length>0||u(Y.options)),!K)return h(),$(n),k;var G=(P.counter||0)+1;return Y.counter=G,T(n,o,Y),r.$$postDigest(function(){var t=L.get(g),r=!t;t=t||{};var i=n.parent()||[],o=i.length>0&&("animate"===t.event||t.structural||u(t.options));if(r||t.counter!==G||!o)return r&&(Q(n,w),v(n,w)),(r||z&&t.event!==e)&&(w.domOperation(),k.end()),void(o||$(n));e=!t.structural&&u(t.options,!0)?"setClass":t.event,T(n,a);var c=d(n,e,t.options);c.done(function(t){h(!t);var r=L.get(g);r&&r.counter===G&&$(_(n)),f(k,e,"close",{})}),k.setHost(c),f(k,e,"start",{})}),k}function N(n){var t=_(n),r=t.querySelectorAll("["+Nn+"]");F(r,function(n){var t=parseInt(n.getAttribute(Nn)),r=L.get(n);if(r)switch(t){case a:r.runner.end();case o:L.remove(n)}})}function $(n){var t=_(n);t.removeAttribute(Nn),L.remove(t)}function j(n,t){return _(n)===_(t)}function D(n,t,r){var e,i=U(s[0].body),u=j(n,i)||"HTML"===n[0].nodeName,o=j(n,f),a=!1,c=R.get(_(n)),l=n.data($n);for(l&&(t=l);t&&t.length;){o||(o=j(t,f));var h=t[0];if(h.nodeType!==K)break;var p=L.get(h)||{};if(!a){var v=R.get(h);if(v===!0&&c!==!1){c=!0;break}v===!1&&(c=!1),a=p.structural}if(Y(e)||e===!0){var g=t.data(rn);Z(g)&&(e=g)}if(a&&e===!1)break;if(u||(u=j(t,i)),u&&o)break;t=o||!(l=t.data($n))?t.parent():l}var d=(!a||e)&&c!==!0;return d&&o&&u}function T(n,t,r){r=r||{},r.state=t;var e=_(n);e.setAttribute(Nn,t);var i=L.get(e),u=i?P(i,r):r;L.put(e,u)}var L=new g,R=new g,O=null,z=r.$watch(function(){return 0===b.totalPendingRequests},function(n){n&&(z(),r.$$postDigest(function(){r.$$postDigest(function(){null===O&&(O=!0)})}))}),q={},V=n.classNameFilter(),J=V?function(n){return V.test(n)}:function(){return!0},Q=h(w),G=Node.prototype.contains||function(n){return this===n||!!(16&this.compareDocumentPosition(n))};return{on:function(n,t,r){var e=l(t);q[n]=q[n]||[],q[n].push({node:e,callback:r})},off:function(n,t,r){function e(n,t,r){var e=l(t);return n.filter(function(n){var t=n.node===e&&(!r||n.callback===r);return!t})}var i=q[n];i&&(q[n]=1===arguments.length?null:e(i,t,r))},pin:function(n,t){e(X(n),"element","not an element"),e(X(t),"parentElement","not an element"),n.data($n,t)},push:function(n,t,r,e){return r=r||{},r.domOperation=e,E(n,t,r)},enabled:function(n,t){var r=arguments.length;if(0===r)t=!!O;else{var e=X(n);if(e){var i=_(n),u=R.get(i);1===r?t=!u:R.put(i,!t)}else t=O=!!n}return t}}}]}],Dn=["$animateProvider",function(n){function t(n,t){n.data(a,t)}function r(n){n.removeData(a)}function e(n){return n.data(a)}var u="ng-animate-ref",o=this.drivers=[],a="$$animationRunner";this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$HashMap","$$rAFScheduler",function(n,a,c,l,f,s){function g(n){function t(n){if(n.processed)return n;n.processed=!0;var r=n.domNode,e=r.parentNode;u.put(r,n);for(var o;e;){if(o=u.get(e)){o.processed||(o=t(o));break}e=e.parentNode}return(o||i).children.push(n),n}function r(n){var t,r=[],e=[];for(t=0;t<n.children.length;t++)e.push(n.children[t]);var i=e.length,u=0,o=[];for(t=0;t<e.length;t++){var a=e[t];0>=i&&(i=u,u=0,r.push(o),o=[]),o.push(a.fn),a.children.forEach(function(n){u++,e.push(n)}),i--}return o.length&&r.push(o),r}var e,i={children:[]},u=new f;for(e=0;e<n.length;e++){var o=n[e];u.put(o.domNode,n[e]={domNode:o.domNode,fn:o.fn,children:[]})}for(e=0;e<n.length;e++)t(n[e]);return r(i)}var d=[],y=h(n);return function(f,h,m){function x(n){var t="["+u+"]",r=n.hasAttribute(u)?[n]:n.querySelectorAll(t),e=[];return F(r,function(n){var t=n.getAttribute(u);t&&t.length&&e.push(n)}),e}function M(n){var t=[],r={};F(n,function(n,e){var i=n.element,o=_(i),a=n.event,c=["enter","move"].indexOf(a)>=0,l=n.structural?x(o):[];if(l.length){var f=c?"to":"from";F(l,function(n){var t=n.getAttribute(u);r[t]=r[t]||{},r[t][f]={animationID:e,element:U(n)}})}else t.push(n)});var e={},i={};return F(r,function(r,u){var o=r.from,a=r.to;if(!o||!a){var c=o?o.animationID:a.animationID,l=c.toString();return void(e[l]||(e[l]=!0,t.push(n[c])))}var f=n[o.animationID],s=n[a.animationID],h=o.animationID.toString();if(!i[h]){var p=i[h]={structural:!0,beforeStart:function(){f.beforeStart(),s.beforeStart()},close:function(){f.close(),s.close()},classes:b(f.classes,s.classes),from:f,to:s,anchors:[]};p.classes.length?t.push(p):(t.push(f),t.push(s))}i[h].anchors.push({out:o.element,"in":a.element})}),t}function b(n,t){n=n.split(" "),t=t.split(" ");for(var r=[],e=0;e<n.length;e++){var i=n[e];if("ng-"!==i.substring(0,3))for(var u=0;u<t.length;u++)if(i===t[u]){r.push(i);break}}return r.join(" ")}function w(n){for(var t=o.length-1;t>=0;t--){var r=o[t];if(c.has(r)){var e=c.get(r),i=e(n);if(i)return i}}}function k(){f.addClass(tn),j&&n.addClass(f,j)}function C(n,t){function r(n){e(n).setHost(t)}n.from&&n.to?(r(n.from.element),r(n.to.element)):r(n.element)}function A(){var n=e(f);!n||"leave"===h&&m.$$domOperationFired||n.end()}function S(t){f.off("$destroy",A),r(f),y(f,m),v(f,m),m.domOperation(),j&&n.removeClass(f,j),f.removeClass(tn),N.complete(!t)}m=p(m);var E=["enter","move","leave"].indexOf(h)>=0,N=new l({end:function(){S()},cancel:function(){S(!0)}});if(!o.length)return S(),N;t(f,N);var $=i(f.attr("class"),i(m.addClass,m.removeClass)),j=m.tempClasses;return j&&($+=" "+j,m.tempClasses=null),d.push({element:f,classes:$,event:h,structural:E,options:m,beforeStart:k,close:S}),f.on("$destroy",A),d.length>1?N:(a.$$postDigest(function(){var n=[];F(d,function(t){e(t.element)?n.push(t):t.close()}),d.length=0;var t=M(n),r=[];F(t,function(n){r.push({domNode:_(n.from?n.from.element:n.element),fn:function(){n.beforeStart();var t,r=n.close,i=n.anchors?n.from.element||n.to.element:n.element;if(e(i)){var u=w(n);u&&(t=u.start)}if(t){var o=t();o.done(function(n){r(!n)}),C(n,o)}else r()}})}),s(g(r))}),N)}}]}];t.module("ngAnimate",[]).directive("ngAnimateChildren",mn).factory("$$rAFScheduler",yn).provider("$$animateQueue",jn).provider("$$animation",Dn).provider("$animateCss",Cn).provider("$$animateCssDriver",An).provider("$$animateJs",Sn).provider("$$animateJsDriver",En)}(window,window.angular);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js b/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js
new file mode 100644
index 0000000..103c7e8
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)>0?i=u:r=u+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function f(n){return(n+="")===bo||n[0]===_o?_o+n:n}function s(n){return(n+="")[0]===_o?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function g(){var n=[];for(var t in this._)n.push(s(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=wo.length;r>e;++e){var i=wo[e]+t;if(i in n)return i}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var e=[],r=new c;return t.on=function(t,i){var u,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,u=e.indexOf(o)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function S(){ao.event.preventDefault()}function k(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function N(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(e,r)}finally{ao.event=u}}},t}function E(n){return ko(n,Co),n}function A(n){return"function"==typeof n?n:function(){return No(n,this)}}function C(n){return"function"==typeof n?n:function(){return Eo(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ao.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?u:i}function L(n){return n.trim().replace(/\s+/g," ")}function q(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=T(n).map(D);var i=n.length;return"function"==typeof t?r:e}function D(n){var t=q(n);return function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",L(i+" "+n))):e.setAttribute("class",L(i.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,e)}function u(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?u:i}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e===zo&&t.documentElement.namespaceURI===zo?t.createElement(n):t.createElementNS(e,n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return Ao(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var i,u=n[e],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,e);return n}function Z(n){return ko(n,qo),n}function V(n){var t,e;return function(r,i,u){var o,a=n[u].update,l=a.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<l;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=l(t,co(arguments));r.call(this),this.addEventListener(n,this[o]=i,i.$=e),i._=t}function u(){var t,e=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var r in this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),l=$;a>0&&(n=n.slice(0,a));var c=To.get(n);return c&&(n=c,l=B),a?t?i:r:t?b:u}function $(n,t){return function(e){var r=ao.event;ao.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Do,i="click"+r,u=ao.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ro&&(Ro="onselectstart"in e?!1:x(e.style,"userSelect")),Ro){var o=n(e).style,a=o[Ro];o[Ro]="none"}return function(n){if(u.on(r,null),Ro&&(o[Ro]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Po){var u=t(n);if(u.scrollX||u.scrollY){r=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Po=!(o.f||o.e),r.remove()}}return Po?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ao.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?Fo:Math.acos(n)}function tn(n){return n>1?Io:-1>n?-Io:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,u=2*e-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,e){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?gn(n.l,n.a,n.b):gn((n=Sn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,e)}function sn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Yo)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):Sn((n=mn(n)).r,n.g,n.b):new hn(n,t,e)}function pn(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=vn(i)*na,r=vn(r)*ta,u=vn(u)*ea,new mn(yn(3.2404542*i-1.5371385*r-.4985314*u),yn(-.969266*i+1.8760108*r+.041556*u),yn(.0556434*i-.2040259*r+1.0572252*u))}function gn(n,t,e){return n>0?new fn(Math.atan2(e,t)*Zo,Math.sqrt(t*t+e*e),n):new fn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,e){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):_n(""+n,mn,cn):new mn(n,t,e)}function Mn(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,i,u,o=0,a=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(Nn(i[0]),Nn(i[1]),Nn(i[2]))}return(u=ua.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,l=15&u,l=l<<4|l):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,l=255&u)),t(o,a,l))}function wn(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-u,l=(o+u)/2;return a?(i=.5>l?a/(o+u):a/(2-o-u),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=NaN,i=l>0&&1>l?0:r),new ln(r,i,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/na),i=dn((.2126729*n+.7151522*t+.072175*e)/ta),u=dn((.0193339*n+.119192*t+.9503041*e)/ea);return hn(116*i-16,500*(r-i),200*(i-u))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function i(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(u,l)}catch(r){return void o.error.call(u,r)}o.load.call(u,n)}else o.error.call(u,l)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=i:l.onreadystatechange=function(){l.readyState>3&&i()},l.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,l)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(c=n,u):c},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(co(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),l.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),l.setRequestHeader)for(var f in a)l.setRequestHeader(f,a[f]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,l),l.send(null==r?null:r),u},u.abort=function(){return l.abort(),u},ao.rebind(u,o,"on"),null==r?u:u.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={c:n,t:i,n:null};return aa?aa.n=u:oa=u,aa=u,la||(ca=clearTimeout(ca),la=1,fa(Tn)),u}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),la=0):(la=1,fa(Tn))}function Rn(){for(var n=Date.now(),t=oa;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=oa,e=1/0;t;)t.c?(t.t<e&&(e=t.t),t=(n=t).n):t=n?n.n=t.n:oa=t.n;return aa=n,e}function Pn(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Un(n,t){var e=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function jn(n){var t=n.decimal,e=n.thousands,r=n.grouping,i=n.currency,u=r&&e?function(n,t){for(var i=n.length,u=[],o=0,a=r[0],l=0;i>0&&a>0&&(l+a+1>t&&(a=Math.max(1,t-l)),u.push(n.substring(i-=a,i+a)),!((l+=a+1)>t));)a=r[o=(o+1)%r.length];return u.reverse().join(e)}:m;return function(n){var e=ha.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",l=e[4]||"",c=e[5],f=+e[6],s=e[7],h=e[8],p=e[9],g=1,v="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===o)&&(c=r="0",o="="),p){case"n":s=!0,p="g";break;case"%":g=100,d="%",p="f";break;case"p":g=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":g=-1,p="r"}"$"===l&&(v=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pa.get(p)||Fn;var M=c&&s;return function(n){var e=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>g){var l=ao.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=g;n=p(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&s&&(x=u(x,1/0));var S=v.length+x.length+b.length+(M?0:i.length),k=f>S?new Array(S=f-S+1).join(r):"";return M&&(x=u(k+x,k.length?f-b.length:1/0)),i+=v,n=x+b,("<"===o?i+n+k:">"===o?k+i+n:"^"===o?k.substring(0,S>>=1)+i+n+k.substring(S):i+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new va(e-1)),1),e}function u(n,e){return t(n=new va(+n),e),n}function o(n,r,u){var o=i(n),a=[];if(u>1)for(;r>o;)e(o)%u||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{va=Hn;var r=new Hn;return r._=n,o(r,t,e)}finally{va=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=o;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(i),l.offset=In(u),l.range=a,n}function In(n){return function(t,e){try{va=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{va=Date}}}function Yn(n){function t(n){function t(t){for(var e,i,u,o=[],a=-1,l=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(l,a)),null!=(i=ya[e=n.charAt(++a)])&&(e=n.charAt(++a)),(u=A[e])&&(e=u(t,null==i?"e"===e?" ":"0":i)),o.push(e),l=a+1);return o.push(n.slice(l,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,n,t,0);if(i!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var u=null!=r.Z&&va!==Hn,o=new(u?Hn:va);return"j"in r?o.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),u?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var i,u,o,a=0,l=t.length,c=e.length;l>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=C[o in ya?t.charAt(a++):o],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function f(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var s=n.dateTime,h=n.date,p=n.time,g=n.periods,v=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function e(n){try{va=Hn;var t=new va;return t._=n,r(t)}finally{va=Date}}var r=t(n);return e.parse=function(n){try{va=Hn;var t=r.parse(n);return t&&t._}finally{va=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=ao.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(y),k=Xn(y),N=Vn(m),E=Xn(m);g.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ga.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return g[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ga.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ga.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},C={a:r,A:i,b:u,B:o,c:a,d:tt,e:tt,H:rt,I:rt,j:et,L:ot,m:nt,M:it,p:f,S:ut,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Vn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function $n(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Bn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function Wn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Jn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Gn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.y=Qn(+r[0]),e+r[0].length):-1}function Kn(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Qn(n){return n+(n>68?1900:2e3)}function nt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function it(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ut(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ot(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function at(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=xo(t)/60|0,i=xo(t)%60;return e+Zn(r,"0",2)+Zn(i,"0",2)}function lt(n,t,e){Ma.lastIndex=0;var r=Ma.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ft(){}function st(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function ht(n,t){n&&wa.hasOwnProperty(n.type)&&wa[n.type](n,t)}function pt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1],r[2]);t.lineEnd()}function gt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)pt(n[e],t,1);t.polygonEnd()}function vt(){function n(n,t){n*=Yo,t=t*Yo/2+Fo/4;var e=n-r,o=e>=0?1:-1,a=o*e,l=Math.cos(t),c=Math.sin(t),f=u*c,s=i*l+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),r=n,i=l,u=c}var t,e,r,i,u;Na.point=function(o,a){Na.point=n,r=(t=o)*Yo,i=Math.cos(a=(e=a)*Yo/2+Fo/4),u=Math.sin(a)},Na.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Uo&&xo(n[1]-t[1])<Uo}function St(n,t){n*=Yo;var e=Math.cos(t*=Yo);kt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function kt(n,t,e){++Ea,Ca+=(n-Ca)/Ea,za+=(t-za)/Ea,La+=(e-La)/Ea}function Nt(){function n(n,i){n*=Yo;var u=Math.cos(i*=Yo),o=u*Math.cos(n),a=u*Math.sin(n),l=Math.sin(i),c=Math.atan2(Math.sqrt((c=e*l-r*a)*c+(c=r*o-t*l)*c+(c=t*a-e*o)*c),t*o+e*a+r*l);Aa+=c,qa+=c*(t+(t=o)),Ta+=c*(e+(e=a)),Ra+=c*(r+(r=l)),kt(t,e,r)}var t,e,r;ja.point=function(i,u){i*=Yo;var o=Math.cos(u*=Yo);t=o*Math.cos(i),e=o*Math.sin(i),r=Math.sin(u),ja.point=n,kt(t,e,r)}}function Et(){ja.point=St}function At(){function n(n,t){n*=Yo;var e=Math.cos(t*=Yo),o=e*Math.cos(n),a=e*Math.sin(n),l=Math.sin(t),c=i*l-u*a,f=u*o-r*l,s=r*a-i*o,h=Math.sqrt(c*c+f*f+s*s),p=r*o+i*a+u*l,g=h&&-nn(p)/h,v=Math.atan2(h,p);Da+=g*c,Pa+=g*f,Ua+=g*s,Aa+=v,qa+=v*(r+(r=o)),Ta+=v*(i+(i=a)),Ra+=v*(u+(u=l)),kt(r,i,u)}var t,e,r,i,u;ja.point=function(o,a){t=o,e=a,ja.point=n,o*=Yo;var l=Math.cos(a*=Yo);r=l*Math.cos(o),i=l*Math.sin(o),u=Math.sin(a),kt(r,i,u)},ja.lineEnd=function(){n(t,e),ja.lineEnd=Et,ja.point=St}}function Ct(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function zt(){return!0}function Lt(n,t,e,r,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(wt(e,r)){i.lineStart();for(var a=0;t>a;++a)i.point((e=n[a])[0],e[1]);return void i.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,u.push(l),o.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,u.push(l),o.push(c)}}),o.sort(t),qt(u),qt(o),u.length){for(var a=0,l=e,c=o.length;c>a;++a)o[a].e=l=!l;for(var f,s,h=u[0];;){for(var p=h,g=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(g)for(var a=0,c=f.length;c>a;++a)i.point((s=f[a])[0],s[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(g){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,g=!g}while(!p.v);i.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r<t;)i.n=e=n[r],e.p=i,i=e;i.n=e=n[0],e.p=i}}function Tt(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Rt(n,t,e,r){return function(i,u){function o(t,e){var r=i(t,e);n(t=r[0],e=r[1])&&u.point(t,e)}function a(n,t){var e=i(n,t);d.point(e[0],e[1])}function l(){m.point=a,d.lineStart()}function c(){m.point=o,d.lineEnd()}function f(n,t){v.push([n,t]);var e=i(n,t);x.point(e[0],e[1])}function s(){x.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),g.push(v),v=null,r)if(1&t){n=e[0];var i,r=n.length-1,o=-1;if(r>0){for(b||(u.polygonStart(),b=!0),u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Dt))}var p,g,v,d=t(u),y=i.invert(r[0],r[1]),m={point:o,lineStart:l,lineEnd:c,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],g=[]},polygonEnd:function(){m.point=o,m.lineStart=l,m.lineEnd=c,p=ao.merge(p);var n=Ot(y,g);p.length?(b||(u.polygonStart(),b=!0),Lt(p,Ut,n,e,u)):n&&(b||(u.polygonStart(),b=!0),u.lineStart(),e(null,null,1,u),u.lineEnd()),b&&(u.polygonEnd(),b=!1),p=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},M=Pt(),x=t(M),b=!1;return m}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ut(n,t){return((n=n.x)[0]<0?n[1]-Io-Uo:Io-n[1])-((t=t.x)[0]<0?t[1]-Io-Uo:Io-t[1])}function jt(n){var t,e=NaN,r=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?Fo:-Fo,l=xo(u-e);xo(l-Fo)<Uo?(n.point(e,r=(r+o)/2>0?Io:-Io),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(u,r),t=0):i!==a&&l>=Fo&&(xo(e-i)<Uo&&(e-=i*Uo),xo(u-a)<Uo&&(u-=a*Uo),r=Ft(e,r,u,o),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=u,r=o),i=a},lineEnd:function(){n.lineEnd(),e=r=NaN},clean:function(){return 2-t}}}function Ft(n,t,e,r){var i,u,o=Math.sin(n-e);return xo(o)>Uo?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+r)/2}function Ht(n,t,e,r){var i;if(null==n)i=e*Io,r.point(-Fo,i),r.point(0,i),r.point(Fo,i),r.point(Fo,0),r.point(Fo,-i),r.point(0,-i),r.point(-Fo,-i),r.point(-Fo,0),r.point(-Fo,i);else if(xo(n[0]-t[0])>Uo){var u=n[0]<t[0]?Fo:-Fo;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(t[0],t[1])}function Ot(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,o=0;ka.reset();for(var a=0,l=t.length;l>a;++a){var c=t[a],f=c.length;if(f)for(var s=c[0],h=s[0],p=s[1]/2+Fo/4,g=Math.sin(p),v=Math.cos(p),d=1;;){d===f&&(d=0),n=c[d];var y=n[0],m=n[1]/2+Fo/4,M=Math.sin(m),x=Math.cos(m),b=y-h,_=b>=0?1:-1,w=_*b,S=w>Fo,k=g*M;if(ka.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),u+=S?b+_*Ho:b,S^h>=e^y>=e){var N=mt(dt(s),dt(n));bt(N);var E=mt(i,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=y,g=M,v=x,s=n}}return(-Uo>u||Uo>u&&0>ka)^1&o}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function e(n){var e,u,l,c,f;return{lineStart:function(){c=l=!1,f=1},point:function(s,h){var p,g=[s,h],v=t(s,h),d=o?v?0:i(s,h):v?i(s+(0>s?Fo:-Fo),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(p=r(e,g),(wt(e,p)||wt(g,p))&&(g[0]+=Uo,g[1]+=Uo,v=t(g[0],g[1]))),v!==l)f=0,v?(n.lineStart(),p=r(g,e),n.point(p[0],p[1])):(p=r(e,g),n.point(p[0],p[1]),n.lineEnd()),e=p;else if(a&&e&&o^v){var y;d&u||!(y=r(g,e,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!v||e&&wt(e,g)||n.point(g[0],g[1]),e=g,l=v,u=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return f|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),i=dt(t),o=[1,0,0],a=mt(r,i),l=yt(a,a),c=a[0],f=l-c*c;if(!f)return!e&&n;var s=u*l/f,h=-u*c/f,p=mt(o,a),g=xt(o,s),v=xt(a,h);Mt(g,v);var d=p,y=yt(g,d),m=yt(d,d),M=y*y-m*(yt(g,g)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-y-x)/m);if(Mt(b,g),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=xo(E-Fo)<Uo,C=A||Uo>E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(xo(b[0]-w)<Uo?k:N):k<=b[1]&&b[1]<=N:E>Fo^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-y+x)/m);return Mt(z,g),[b,_t(z)]}}}function i(t,e){var r=o?n:Fo-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Uo,l=ve(n,6*Yo);return Rt(t,e,l,o?[0,-n]:[-Fo,n-Fo])}function Yt(n,t,e,r){return function(i){var u,o=i.a,a=i.b,l=o.x,c=o.y,f=a.x,s=a.y,h=0,p=1,g=f-l,v=s-c;if(u=n-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}if(u=t-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:l+h*g,y:c+h*v}),1>p&&(i.b={x:l+p*g,y:c+p*v}),i}}}}}}function Zt(n,t,e,r){function i(r,i){return xo(r[0]-n)<Uo?i>0?0:3:xo(r[0]-e)<Uo?i>0?2:1:xo(r[1]-t)<Uo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function l(n){for(var t=0,e=d.length,r=n[1],i=0;e>i;++i)for(var u,o=1,a=d[i],l=a.length,c=a[0];l>o;++o)u=a[o],c[1]<=r?u[1]>r&&Q(c,u,n)>0&&++t:u[1]<=r&&Q(c,u,n)<0&&--t,c=u;return 0!==t}function c(u,a,l,c){var f=0,s=0;if(null==u||(f=i(u,l))!==(s=i(a,l))||o(u,a)<0^l>0){do c.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+l+4)%4)!==s)}else c.point(a[0],a[1])}function f(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){C.point=g,d&&d.push(y=[]),S=!0,w=!1,b=_=NaN}function p(){v&&(g(m,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=s,w&&a.lineEnd()}function g(n,t){n=Math.max(-Ha,Math.min(Ha,n)),t=Math.max(-Ha,Math.min(Ha,t));var e=f(n,t);if(d&&y.push([n,t]),S)m=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,y,m,M,x,b,_,w,S,k,N=a,E=Pt(),A=Yt(n,t,e,r),C={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=E,v=[],d=[],k=!0},polygonEnd:function(){a=N,v=ao.merge(v);var t=l([n,r]),e=k&&t,i=v.length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),c(null,null,1,a),a.lineEnd()),i&&Lt(v,u,t,c,a),a.polygonEnd()),v=d=y=null}};return C}}function Vt(n){var t=0,e=Fo/3,r=ae(n),i=r(t,e);return i.parallels=function(n){return arguments.length?r(t=n[0]*Fo/180,e=n[1]*Fo/180):[t/Fo*180,e/Fo*180]},i}function Xt(n,t){function e(n,t){var e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),o-e*Math.cos(n)]}var r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),o=Math.sqrt(u)/i;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/i,tn((u-(n*n+e*e)*i*i)/(2*i))]},e}function $t(){function n(n,t){Ia+=i*n-r*t,r=n,i=t}var t,e,r,i;$a.point=function(u,o){$a.point=n,t=r=u,e=i=o},$a.lineEnd=function(){n(t,e)}}function Bt(n,t){Ya>n&&(Ya=n),n>Va&&(Va=n),Za>t&&(Za=t),t>Xa&&(Xa=t)}function Wt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function i(){o.push("Z")}var u=Jt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return u=Jt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ca+=n,za+=t,++La}function Kt(){function n(n,r){var i=n-t,u=r-e,o=Math.sqrt(i*i+u*u);qa+=o*(t+n)/2,Ta+=o*(e+r)/2,Ra+=o,Gt(t=n,e=r)}var t,e;Wa.point=function(r,i){Wa.point=n,Gt(t=r,e=i)}}function Qt(){Wa.point=Gt}function ne(){function n(n,t){var e=n-r,u=t-i,o=Math.sqrt(e*e+u*u);qa+=o*(r+n)/2,Ta+=o*(i+t)/2,Ra+=o,o=i*n-r*t,Da+=o*(r+n),Pa+=o*(i+t),Ua+=3*o,Gt(r=n,i=t)}var t,e,r,i;Wa.point=function(u,o){Wa.point=n,Gt(t=r=u,e=i=o)},Wa.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,Ho)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function ee(n){function t(n){return(a?r:e)(n)}function e(t){return ue(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=u,t.lineStart()}function u(e,r){var u=dt([e,r]),o=n(e,r);i(M,x,m,b,_,w,M=o[0],x=o[1],m=e,b=u[0],_=u[1],w=u[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function l(){
+r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r-h)<Uo?(r+h)/2:Math.atan2(_,b),E=n(N,k),A=E[0],C=E[1],z=A-t,L=C-e,q=M*z-m*L;(q*q/x>u||xo((m*z+M*L)/x-.5)>.3||o>a*p+l*g+c*v)&&(i(t,e,r,a,l,c,A,C,N,b/=S,_/=S,w,d,y),y.point(A,C),i(A,C,N,b,_,w,f,s,h,p,g,v,d,y))}}var u=.5,o=Math.cos(30*Yo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function re(n){var t=ee(function(t,e){return n([t*Zo,e*Zo])});return function(n){return le(t(n))}}function ie(n){this.stream=n}function ue(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function oe(n){return ae(function(){return n})()}function ae(n){function t(n){return n=a(n[0]*Yo,n[1]*Yo),[n[0]*h+l,c-n[1]*h]}function e(n){return n=a.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Zo,n[1]*Zo]}function r(){a=Ct(o=se(y,M,x),u);var n=u(v,d);return l=p-n[0]*h,c=g+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,l,c,f,s=ee(function(n,t){return n=u(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,p=480,g=250,v=0,d=0,y=0,M=0,x=0,b=Fa,_=m,w=null,S=null;return t.stream=function(n){return f&&(f.valid=!1),f=le(b(o,s(_(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Fa):It((w=+n)*Yo),i()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(p=+n[0],g=+n[1],r()):[p,g]},t.center=function(n){return arguments.length?(v=n[0]%360*Yo,d=n[1]%360*Yo,r()):[v*Zo,d*Zo]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Yo,M=n[1]%360*Yo,x=n.length>2?n[2]%360*Yo:0,r()):[y*Zo,M*Zo,x*Zo]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function le(n){return ue(n,function(t,e){n.point(t*Yo,e*Yo)})}function ce(n,t){return[n,t]}function fe(n,t){return[n>Fo?n-Ho:-Fo>n?n+Ho:n,t]}function se(n,t,e){return n?t||e?Ct(pe(n),ge(t,e)):pe(n):t||e?ge(t,e):fe}function he(n){return function(t,e){return t+=n,[t>Fo?t-Ho:-Fo>t?t+Ho:t,e]}}function pe(n){var t=he(n);return t.invert=he(-n),t}function ge(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*r+a*i;return[Math.atan2(l*u-f*o,a*r-c*i),tn(f*u+l*o)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*u-l*o;return[Math.atan2(l*u+c*o,a*r+f*i),tn(f*r-a*i)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,o,a){var l=o*t;null!=i?(i=de(e,i),u=de(e,u),(o>0?u>i:i>u)&&(i+=o*Ho)):(i=n+o*Ho,u=n-.5*l);for(var c,f=i;o>0?f>u:u>f;f-=l)a.point((c=_t([e,-r*Math.cos(f),-r*Math.sin(f)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Uo)%(2*Math.PI)}function ye(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function me(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(r),a=Math.sin(r),l=i*Math.cos(n),c=i*Math.sin(n),f=o*Math.cos(e),s=o*Math.sin(e),h=2*Math.asin(Math.sqrt(on(r-t)+i*o*on(e-n))),p=1/Math.sin(h),g=h?function(n){var t=Math.sin(n*=h)*p,e=Math.sin(h-n)*p,r=e*l+t*f,i=e*c+t*s,o=e*u+t*a;return[Math.atan2(i,r)*Zo,Math.atan2(o,Math.sqrt(r*r+i*i))*Zo]}:function(){return[n*Zo,t*Zo]};return g.distance=h,g}function _e(){function n(n,i){var u=Math.sin(i*=Yo),o=Math.cos(i),a=xo((n*=Yo)-t),l=Math.cos(a);Ja+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*u-e*o*l)*a),e*u+r*o*l),t=n,e=u,r=o}var t,e,r;Ga.point=function(i,u){t=i*Yo,e=Math.sin(u*=Yo),r=Math.cos(u),Ga.point=n},Ga.lineEnd=function(){Ga.point=Ga.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,r*o),Math.asin(r&&e*u/r)]},e}function Se(n,t){function e(n,t){o>0?-Io+Uo>t&&(t=-Io+Uo):t>Io-Uo&&(t=Io-Uo);var e=o/Math.pow(i(t),u);return[e*Math.sin(u*n),o-e*Math.cos(u*n)]}var r=Math.cos(n),i=function(n){return Math.tan(Fo/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),o=r*Math.pow(i(n),u)/u;return u?(e.invert=function(n,t){var e=o-t,r=K(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(o/r,1/u))-Io]},e):Ne}function ke(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return xo(i)<Uo?ce:(e.invert=function(n,t){var e=u-t;return[Math.atan2(n,e)/i,u-K(i)*Math.sqrt(n*n+e*e)]},e)}function Ne(n,t){return[n,Math.log(Math.tan(Fo/4+t/2))]}function Ee(n){var t,e=oe(n),r=e.scale,i=e.translate,u=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=u.apply(e,arguments);if(o===e){if(t=null==n){var a=Fo*r(),l=i();u([[l[0]-a,l[1]-a],[l[0]+a,l[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ae(n,t){return[Math.log(Math.tan(Fo/4+t/2)),-n]}function Ce(n){return n[0]}function ze(n){return n[1]}function Le(n){for(var t=n.length,e=[0,1],r=2,i=2;t>i;i++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var i=n[0],u=e[0],o=t[0]-i,a=r[0]-u,l=n[1],c=e[1],f=t[1]-l,s=r[1]-c,h=(a*(l-c)-s*(i-u))/(s*o-a*f);return[i+h*o,l+h*f]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function Ue(n){var t=cl.pop()||new Pe;return t.site=n,t}function je(n){Be(n),ol.remove(n),cl.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,i={x:e,y:r},u=n.P,o=n.N,a=[n];je(n);for(var l=u;l.circle&&xo(e-l.circle.x)<Uo&&xo(r-l.circle.cy)<Uo;)u=l.P,a.unshift(l),je(l),l=u;a.unshift(l),Be(l);for(var c=o;c.circle&&xo(e-c.circle.x)<Uo&&xo(r-c.circle.cy)<Uo;)o=c.N,a.push(c),je(c),c=o;a.push(c),Be(c);var f,s=a.length;for(f=1;s>f;++f)c=a[f],l=a[f-1],nr(c.edge,l.site,c.site,i);l=a[0],c=a[s-1],c.edge=Ke(l.site,c.site,null,i),$e(l),$e(c)}function He(n){for(var t,e,r,i,u=n.x,o=n.y,a=ol._;a;)if(r=Oe(a,o)-u,r>Uo)a=a.L;else{if(i=u-Ie(a,o),!(i>Uo)){r>-Uo?(t=a.P,e=a):i>-Uo?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var l=Ue(n);if(ol.insert(t,l),t||e){if(t===e)return Be(t),e=Ue(t.site),ol.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,f=c.x,s=c.y,h=n.x-f,p=n.y-s,g=e.site,v=g.x-f,d=g.y-s,y=2*(h*d-p*v),m=h*h+p*p,M=v*v+d*d,x={x:(d*m-p*M)/y+f,y:(h*M-v*m)/y+s};nr(e.edge,c,g,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,g,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,i=e.y,u=i-t;if(!u)return r;var o=n.P;if(!o)return-(1/0);e=o.site;var a=e.x,l=e.y,c=l-t;if(!c)return a;var f=a-r,s=1/u-1/c,h=f/c;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*c)-l+c/2+i-u/2)))/s+r:(r+a)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,i,u,o,a,l,c,f,s=n[0][0],h=n[1][0],p=n[0][1],g=n[1][1],v=ul,d=v.length;d--;)if(u=v[d],u&&u.prepare())for(a=u.edges,l=a.length,o=0;l>o;)f=a[o].end(),r=f.x,i=f.y,c=a[++o%l].start(),t=c.x,e=c.y,(xo(r-t)>Uo||xo(i-e)>Uo)&&(a.splice(o,0,new tr(Qe(u.site,f,xo(r-s)<Uo&&g-i>Uo?{x:s,y:xo(t-s)<Uo?e:g}:xo(i-g)<Uo&&h-r>Uo?{x:xo(e-g)<Uo?t:h,y:g}:xo(r-h)<Uo&&i-p>Uo?{x:h,y:xo(t-h)<Uo?e:p}:xo(i-p)<Uo&&r-s>Uo?{x:xo(e-p)<Uo?t:s,y:p}:null),u.site,null)),++l)}function Ve(n,t){return t.angle-n.angle}function Xe(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function $e(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,i=n.site,u=e.site;if(r!==u){var o=i.x,a=i.y,l=r.x-o,c=r.y-a,f=u.x-o,s=u.y-a,h=2*(l*s-c*f);if(!(h>=-jo)){var p=l*l+c*c,g=f*f+s*s,v=(s*p-c*g)/h,d=(l*g-f*p)/h,s=d+a,y=fl.pop()||new Xe;y.arc=n,y.site=i,y.x=v+o,y.y=s+Math.sqrt(v*v+d*d),y.cy=s,n.circle=y;for(var m=null,M=ll._;M;)if(y.y<M.y||y.y===M.y&&y.x<=M.x){if(!M.L){m=M.P;break}M=M.L}else{if(!M.R){m=M;break}M=M.R}ll.insert(m,y),m||(al=y)}}}}function Be(n){var t=n.circle;t&&(t.P||(al=t.N),ll.remove(t),fl.push(t),rr(t),n.circle=null)}function We(n){for(var t,e=il,r=Yt(n[0][0],n[0][1],n[1][0],n[1][1]),i=e.length;i--;)t=e[i],(!Je(t,n)||!r(t)||xo(t.a.x-t.b.x)<Uo&&xo(t.a.y-t.b.y)<Uo)&&(t.a=t.b=null,e.splice(i,1))}function Je(n,t){var e=n.b;if(e)return!0;var r,i,u=n.a,o=t[0][0],a=t[1][0],l=t[0][1],c=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,g=s.x,v=s.y,d=(h+g)/2,y=(p+v)/2;if(v===p){if(o>d||d>=a)return;if(h>g){if(u){if(u.y>=c)return}else u={x:d,y:l};e={x:d,y:c}}else{if(u){if(u.y<l)return}else u={x:d,y:c};e={x:d,y:l}}}else if(r=(h-g)/(v-p),i=y-r*d,-1>r||r>1)if(h>g){if(u){if(u.y>=c)return}else u={x:(l-i)/r,y:l};e={x:(c-i)/r,y:c}}else{if(u){if(u.y<l)return}else u={x:(c-i)/r,y:c};e={x:(l-i)/r,y:l}}else if(v>p){if(u){if(u.x>=a)return}else u={x:o,y:r*o+i};e={x:a,y:r*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:r*a+i};e={x:o,y:r*o+i}}return n.a=u,n.b=e,!0}function Ge(n,t){this.l=n,this.r=t,this.a=this.b=null}function Ke(n,t,e,r){var i=new Ge(n,t);return il.push(i),e&&nr(i,n,t,e),r&&nr(i,t,n,r),ul[n.i].edges.push(new tr(i,n,t)),ul[t.i].edges.push(new tr(i,t,n)),i}function Qe(n,t,e){var r=new Ge(n,null);return r.a=t,r.b=e,il.push(r),r}function nr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function tr(n,t,e){var r=n.a,i=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ir(n,t){var e=t,r=t.R,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ur(n,t){var e=t,r=t.L,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function or(n){for(;n.L;)n=n.L;return n}function ar(n,t){var e,r,i,u=n.sort(lr).pop();for(il=[],ul=new Array(n.length),ol=new er,ll=new er;;)if(i=al,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===e&&u.y===r||(ul[u.i]=new Ye(u),He(u),e=u.x,r=u.y),u=n.pop();else{if(!i)break;Fe(i.arc)}t&&(We(t),Ze(t));var o={cells:ul,edges:il};return ol=ll=il=ul=null,o}function lr(n,t){return t.y-n.y||t.x-n.x}function cr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function fr(n){return n.x}function sr(n){return n.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var o=.5*(e+i),a=.5*(r+u),l=t.nodes;l[0]&&pr(n,l[0],e,r,o,a),l[1]&&pr(n,l[1],o,r,i,a),l[2]&&pr(n,l[2],e,a,o,u),l[3]&&pr(n,l[3],o,a,i,u)}}function gr(n,t,e,r,i,u,o){var a,l=1/0;return function c(n,f,s,h,p){if(!(f>u||s>o||r>h||i>p)){if(g=n.point){var g,v=t-n.x,d=e-n.y,y=v*v+d*d;if(l>y){var m=Math.sqrt(l=y);r=t-m,i=e-m,u=t+m,o=e+m,a=g}}for(var M=n.nodes,x=.5*(f+h),b=.5*(s+p),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,f,s,x,b);break;case 1:c(n,x,s,h,b);break;case 2:c(n,f,b,x,p);break;case 3:c(n,x,b,h,p)}}}(n,r,i,u,o),a}function vr(n,t){n=ao.rgb(n),t=ao.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,o=t.g-r,a=t.b-i;return function(n){return"#"+bn(Math.round(e+u*n))+bn(Math.round(r+o*n))+bn(Math.round(i+a*n))}}function dr(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function yr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function mr(n,t){var e,r,i,u=hl.lastIndex=pl.lastIndex=0,o=-1,a=[],l=[];for(n+="",t+="";(e=hl.exec(n))&&(r=pl.exec(t));)(i=r.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,l.push({i:o,x:yr(e,r)})),u=pl.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?l[0]?(t=l[0].x,function(n){return t(n)+""}):function(){return t}:(t=l.length,function(n){for(var e,r=0;t>r;++r)a[(e=l[r]).i]=e.x(n);return a.join("")})}function Mr(n,t){for(var e,r=ao.interpolators.length;--r>=0&&!(e=ao.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Mr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;o>e;++e)i[e]=t[e];return function(n){for(e=0;a>e;++e)i[e]=r[e](n);return i}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Io)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ho*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ho/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=ao.hcl(n),t=ao.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,o=t.c-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(e+u*n,r+o*n,i+a*n)+""}}function Dr(n,t){n=ao.hsl(n),t=ao.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,o=t.s-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return cn(e+u*n,r+o*n,i+a*n)+""}}function Pr(n,t){n=ao.lab(n),t=ao.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,o=t.a-r,a=t.b-i;return function(n){return pn(e+u*n,r+o*n,i+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function jr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),i=Fr(t,e),u=Hr(Or(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Zo,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Zo:0}function Fr(n,t){return n[0]*t[0]+n[1]*t[1]}function Hr(n){var t=Math.sqrt(Fr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Or(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Ir(n){return n.length?n.pop()+",":""}function Yr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else(t[0]||t[1])&&e.push("translate("+t+")")}function Zr(n,t,e,r){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:yr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:yr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else 1===t[0]&&1===t[1]||e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=ao.transform(n),t=ao.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,i=-1,u=r.length;++i<u;)e[(t=r[i]).i]=t.x(n);return e.join("")}}function Br(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Wr(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Jr(n){for(var t=n.source,e=n.target,r=Kr(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Gr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Kr(n,t){if(n===t)return n;for(var e=Gr(n),r=Gr(t),i=e.pop(),u=r.pop(),o=null;i===u;)o=i,i=e.pop(),u=r.pop();return o}function Qr(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ei(n){n.fixed&=-5}function ri(n,t,e){var r=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,l=-1;++l<a;)u=o[l],null!=u&&(ri(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var c=t*e[n.point.index];n.charge+=n.pointCharge=c,r+=c*n.point.x,i+=c*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(i=n.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function oi(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)e.push(u[o]);for(;null!=(n=r.pop());)t(n)}function ai(n){return n.children}function li(n){return n.value}function ci(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,e){n.y0=t,n.y=e}function gi(n){return ao.range(n.length)}function vi(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function di(n){for(var t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function Mi(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function bi(n){return[ao.min(n),ao.max(n)]}function _i(n,t){return n.value-t.value}function wi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Si(n,t){n._pack_next=t,t._pack_prev=n}function ki(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ni(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((e=n.children)&&(c=e.length)){var e,r,i,u,o,a,l,c,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(e.forEach(Ei),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(i=e[1],i.x=i.r,i.y=0,t(i),c>2))for(u=e[2],zi(r,i,u),t(u),wi(r,u),r._pack_prev=u,wi(u,i),i=r._pack_next,o=3;c>o;o++){zi(r,i,u=e[o]);var g=0,v=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,v++)if(ki(a,u)){g=1;break}if(1==g)for(l=r._pack_prev;l!==a._pack_prev&&!ki(l,u);l=l._pack_prev,d++);g?(d>v||v==d&&i.r<r.r?Si(r,i=a):Si(r=l,i),o--):(wi(r,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,M=0;for(o=0;c>o;o++)u=e[o],u.x-=y,u.y-=m,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Ai)}}function Ei(n){n._pack_next=n._pack_prev=n}function Ai(n){delete n._pack_next,delete n._pack_prev}function Ci(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,o=i.length;++u<o;)Ci(i[u],t,e,r)}function zi(n,t,e){var r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var o=t.r+e.r,a=i*i+u*u;o*=o,r*=r;var l=.5+(r-o)/(2*a),c=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+l*i+c*u,e.y=n.y+l*u-c*i}else e.x=n.x+r,e.y=n.y}function Li(n,t){return n.parent==t.parent?1:2}function qi(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ri(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Di(n){for(var t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pi(n,t,e){return n.a.parent===t.parent?n.a:e}function Ui(n){return 1+ao.max(n,function(n){return n.y})}function ji(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return t&&t.length?Fi(t[0]):n}function Hi(n){var t,e=n.children;return e&&(t=e.length)?Hi(e[t-1]):n}function Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ii(n,t){var e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zi(n){return n.rangeExtent?n.rangeExtent():Yi(n.range())}function Vi(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Xi(n,t){var e,r=0,i=n.length-1,u=n[r],o=n[i];return u>o&&(e=r,r=i,i=e,e=u,u=o,o=e),n[r]=t.floor(u),n[i]=t.ceil(o),n}function $i(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Sl}function Bi(n,t,e,r){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(e(n[o-1],n[o])),u.push(r(t[o-1],t[o]));return function(t){var e=ao.bisect(n,t,1,a)-1;return u[e](i[e](t))}}function Wi(n,t,e,r){function i(){var i=Math.min(n.length,t.length)>2?Bi:Vi,l=r?Wr:Br;return o=i(n,t,l,e),a=i(t,n,l,Mr),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return Qi(n,t)},u.tickFormat=function(t,e){return nu(n,t,e)},u.nice=function(t){return Gi(n,t),i()},u.copy=function(){return Wi(n,t,e,r)},i()}function Ji(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gi(n,t){return Xi(n,$i(Ki(n,t)[2])),Xi(n,$i(Ki(n,t)[2])),n}function Ki(n,t){null==t&&(t=10);var e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(n,t){return ao.range.apply(ao,Ki(n,t))}function nu(n,t,e){var r=Ki(n,t);if(e){var i=ha.exec(e);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(r[0]),xo(r[1])));return i[7]||(i[7]="."+tu(u.scale(r[2]))),i[8]="f",e=ao.format(i.join("")),function(n){return e(u.scale(n))+u.symbol}}i[7]||(i[7]="."+eu(i[8],r)),e=i.join("")}else e=",."+tu(r[2])+"f";return ao.format(e)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function eu(n,t){var e=tu(t[2]);return n in kl?Math.abs(e-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ru(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),o):t},o.nice=function(){var t=Xi(r.map(i),e?Math:El);return n.domain(t),r=t.map(u),o},o.ticks=function(){var n=Yi(r),o=[],a=n[0],l=n[1],c=Math.floor(i(a)),f=Math.ceil(i(l)),s=t%1?2:t;if(isFinite(f-c)){if(e){for(;f>c;c++)for(var h=1;s>h;h++)o.push(u(c)*h);o.push(u(c))}else for(o.push(u(c));c++<f;)for(var h=s-1;h>0;h--)o.push(u(c)*h);for(c=0;o[c]<a;c++);for(f=o.length;o[f-1]>l;f--);o=o.slice(c,f)}return o},o.tickFormat=function(n,e){if(!arguments.length)return Nl;arguments.length<2?e=Nl:"function"!=typeof e&&(e=ao.format(e));var r=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),r>=o?e(n):""}},o.copy=function(){return ru(n.copy(),t,e,r)},Ji(o,n)}function iu(n,t,e){function r(t){return n(i(t))}var i=uu(t),u=uu(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return Qi(e,n)},r.tickFormat=function(n,t){return nu(e,n,t)},r.nice=function(n){return r.domain(Gi(e,n))},r.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return iu(n.copy(),t,e)},Ji(r,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(e){return u[((i.get(e)||("range"===t.t?i.set(e,n.push(e)):NaN))-1)%u.length]}function r(t,e){return ao.range(n.length).map(function(n){return t+e*n})}var i,u,o;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new c;for(var u,o=-1,a=r.length;++o<a;)i.has(u=r[o])||i.set(u,n.push(u));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},e):u},e.rangePoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=(l+c)/2,0):(c-l)/(n.length-1+a);return u=r(l+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=c=Math.round((l+c)/2),0):(c-l)/(n.length-1+a)|0;return u=r(l+Math.round(f*a/2+(c-l-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=(s-f)/(n.length-a+2*l);return u=r(f+h*l,h),c&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=Math.floor((s-f)/(n.length-a+2*l));return u=r(f+Math.round((s-f-(n.length-a)*h)/2),h),c&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return ou(n,t)},e.domain(n)}function au(n,t){function u(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ao.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(i).sort(e),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[NaN,NaN]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function lu(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=e.length/(t-n),o=e.length-1,r}var u,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return arguments.length?(e=n,i()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},r.copy=function(){return lu(n,t,e)},i()}function cu(n,t){function e(e){return e>=e?t[ao.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return cu(n,t)},e}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qi(n,t)},t.tickFormat=function(t,e){return nu(n,t,e)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function gu(n){return n.startAngle}function vu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function mu(n,t,e,r,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?r:-r)/Math.sqrt(u*u+o*o),l=a*o,c=-a*u,f=n[0]+l,s=n[1]+c,h=t[0]+l,p=t[1]+c,g=(f+h)/2,v=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,M=e-r,x=f*p-h*s,b=(0>y?-1:1)*Math.sqrt(Math.max(0,M*M*m-x*x)),_=(x*y-d*b)/m,w=(-x*d-y*b)/m,S=(x*y+d*b)/m,k=(-x*d+y*b)/m,N=_-g,E=w-v,A=S-g,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mu(n){function t(t){function o(){c.push("M",u(n(f),a))}for(var l,c=[],f=[],s=-1,h=t.length,p=En(e),g=En(r);++s<h;)i.call(this,l=t[s],s)?f.push([+p.call(this,l,s),+g.call(this,l,s)]):f.length&&(o(),f=[]);return f.length&&o(),c.length?c.join(""):null}var e=Ce,r=ze,i=zt,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Tl.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function bu(n){return n.join("L")+"Z"}function _u(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function wu(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return i.join("")}function Su(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return i.join("")}function ku(n,t){return n.length<4?xu(n):n[1]+Au(n.slice(1,-1),Cu(n,t))}function Nu(n,t){return n.length<3?bu(n):n[0]+Au((n.push(n[0]),n),Cu([n[n.length-2]].concat(n,[n[1]]),t))}function Eu(n,t){return n.length<3?xu(n):n[0]+Au(n,Cu(n,t))}function Au(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var e=n.length!=t.length,r="",i=n[0],u=n[1],o=t[0],a=o,l=1;if(e&&(r+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],l=2),t.length>1){a=t[1],u=n[l],l++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var c=2;c<t.length;c++,l++)u=n[l],a=t[c],r+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(e){var f=n[l];r+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return r}function Cu(n,t){for(var e,r=[],i=(1-t)/2,u=n[0],o=n[1],a=1,l=n.length;++a<l;)e=u,u=o,o=n[a],r.push([i*(o[0]-e[0]),i*(o[1]-e[1])]);return r}function zu(n){if(n.length<3)return xu(n);var t=1,e=n.length,r=n[0],i=r[0],u=r[1],o=[i,i,i,(r=n[1])[0]],a=[u,u,u,r[1]],l=[i,",",u,"L",Ru(Pl,o),",",Ru(Pl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Du(l,o,a);return n.pop(),l.push("L",r),l.join("")}function Lu(n){if(n.length<4)return xu(n);for(var t,e=[],r=-1,i=n.length,u=[0],o=[0];++r<3;)t=n[r],u.push(t[0]),o.push(t[1]);for(e.push(Ru(Pl,u)+","+Ru(Pl,o)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Du(e,u,o);return e.join("")}function qu(n){for(var t,e,r=-1,i=n.length,u=i+4,o=[],a=[];++r<4;)e=n[r%i],o.push(e[0]),a.push(e[1]);for(t=[Ru(Pl,o),",",Ru(Pl,a)],--r;++r<u;)e=n[r%i],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Du(t,o,a);return t.join("")}function Tu(n,t){var e=n.length-1;if(e)for(var r,i,u=n[0][0],o=n[0][1],a=n[e][0]-u,l=n[e][1]-o,c=-1;++c<=e;)r=n[c],i=c/e,r[0]=t*r[0]+(1-t)*(u+i*a),r[1]=t*r[1]+(1-t)*(o+i*l);return zu(n)}function Ru(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Du(n,t,e){n.push("C",Ru(Rl,t),",",Ru(Rl,e),",",Ru(Dl,t),",",Ru(Dl,e),",",Ru(Pl,t),",",Ru(Pl,e))}function Pu(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Uu(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],o=r[0]=Pu(i,u);++t<e;)r[t]=(o+(o=Pu(i=u,u=n[t+1])))/2;return r[t]=o,r}function ju(n){for(var t,e,r,i,u=[],o=Uu(n),a=-1,l=n.length-1;++a<l;)t=Pu(n[a],n[a+1]),xo(t)<Uo?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*e,o[a+1]=i*r));for(a=-1;++a<=l;)i=(n[Math.min(l,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Fu(n){return n.length<3?xu(n):n[0]+Au(n,ju(n))}function Hu(n){for(var t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]-Io,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Ou(n){function t(t){function l(){v.push("M",a(n(y),s),f,c(n(d.reverse()),s),"Z")}for(var h,p,g,v=[],d=[],y=[],m=-1,M=t.length,x=En(e),b=En(i),_=e===r?function(){
+return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(l="function"==typeof n?a=n:(a=Tl.get(n)||xu).key,c=a.reverse||a,f=a.closed?"M":"L",t):l},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Iu(n){return n.radius}function Yu(n){return[n.x,n.y]}function Zu(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Io;return[e*Math.cos(r),e*Math.sin(r)]}}function Vu(){return 64}function Xu(){return"circle"}function $u(n){var t=Math.sqrt(n/Fo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Bu(n){return function(){var t,e,r;(t=this[n])&&(r=t[e=t.active])&&(r.timer.c=null,r.timer.t=NaN,--t.count?delete t[e]:delete this[n],t.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Wu(n,t,e){return ko(n,Yl),n.namespace=t,n.id=e,n}function Ju(n,t,e,r){var i=n.id,u=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[u][i].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[u][i].tween.set(t,e)}))}function Gu(n){return null==n&&(n=""),function(){this.textContent=n}}function Ku(n){return null==n?"__transition__":"__transition_"+n+"__"}function Qu(n,t,e,r,i){function u(n){var t=v.delay;return f.t=t+l,n>=t?o(n-t):void(f.c=o)}function o(e){var i=g.active,u=g[i];u&&(u.timer.c=null,u.timer.t=NaN,--g.count,delete g[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in g)if(r>+o){var c=g[o];c.timer.c=null,c.timer.t=NaN,--g.count,delete g[o]}f.c=a,qn(function(){return f.c&&a(e||1)&&(f.c=null,f.t=NaN),1},0,l),g.active=r,v.event&&v.event.start.call(n,n.__data__,t),p=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&p.push(r)}),h=v.ease,s=v.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(v.event&&v.event.end.call(n,n.__data__,t),--g.count?delete g[r]:delete n[e],1):void 0}var l,f,s,h,p,g=n[e]||(n[e]={active:0,count:0}),v=g[r];v||(l=i.time,f=qn(u,0,l),v=g[r]={tween:new c,time:l,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++g.count)}function no(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function to(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function eo(n){return n.toISOString()}function ro(n,t,e){function r(t){return n(t)}function i(n,e){var r=n[1]-n[0],i=r/e,u=ao.bisect(Kl,i);return u==Kl.length?[t.year,Ki(n.map(function(n){return n/31536e6}),e)[2]]:u?t[i/Kl[u-1]<Kl[u]/i?u-1:u]:[tc,Ki(n,e)[2]]}return r.invert=function(t){return io(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(io)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,io(+e+1),t).length}var u=r.domain(),o=Yi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),r.domain(Xi(u,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yi(r.domain()),u=null==n?i(e,10):"number"==typeof n?i(e,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(e[0],io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ro(n.copy(),t,e)},Ji(r,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.16"},lo=[].slice,co=function(n){return lo.call(n)},fo=this.document;if(fo)try{co(fo.documentElement.childNodes)[0].nodeType}catch(so){co=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,go=po.setAttribute,vo=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){go.call(this,n,t+"")},po.setAttributeNS=function(n,t,e){vo.call(this,n,t,e+"")},yo.setProperty=function(n,t,e){mo.call(this,n,t+"",e)}}ao.ascending=e,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return e},ao.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&r>e&&(e=r)}return e},ao.extent=function(n,t){var e,r,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(r=n[u])&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<o;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},ao.sum=function(n,t){var e,r=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(e=+n[o])&&(r+=e);else for(;++o<u;)i(e=+t.call(n,n[o],o))&&(r+=e);return r},ao.mean=function(n,t){var e,u=0,o=n.length,a=-1,l=o;if(1===arguments.length)for(;++a<o;)i(e=r(n[a]))?u+=e:--l;else for(;++a<o;)i(e=r(t.call(n,n[a],a)))?u+=e:--l;return l?u/l:void 0},ao.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return u?i+u*(n[r]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,l=-1;if(1===arguments.length)for(;++l<a;)i(u=r(n[l]))&&o.push(u);else for(;++l<a;)i(u=r(t.call(n,n[l],l)))&&o.push(u);return o.length?ao.quantile(o.sort(e),.5):void 0},ao.variance=function(n,t){var e,u,o=n.length,a=0,l=0,c=-1,f=0;if(1===arguments.length)for(;++c<o;)i(e=r(n[c]))&&(u=e-a,a+=u/++f,l+=u*(e-a));else for(;++c<o;)i(e=r(t.call(n,n[c],c)))&&(u=e-a,a+=u/++f,l+=u*(e-a));return f>1?l/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var Mo=u(e);ao.bisectLeft=Mo.left,ao.bisect=ao.bisectRight=Mo.right,ao.bisector=function(n){return u(1===n.length?function(t,r){return e(n(t),r)}:n)},ao.shuffle=function(n,t,e){(u=arguments.length)<3&&(e=n.length,2>u&&(t=0));for(var r,i,u=e-t;u;)i=Math.random()*u--|0,r=n[u+t],n[u+t]=n[i+t],n[i+t]=r;return n},ao.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ao.pairs=function(n){for(var t,e=0,r=n.length-1,i=n[0],u=new Array(0>r?0:r);r>e;)u[e]=[t=i,i=n[++e]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,e=ao.min(n,o),r=new Array(e);++t<e;)for(var i,u=-1,a=r[t]=new Array(i);++u<i;)a[u]=n[u][t];return r},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ao.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ao.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ao.merge=function(n){for(var t,e,r,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(e=new Array(o);--i>=0;)for(r=n[i],t=r.length;--t>=0;)e[--o]=r[t];return e};var xo=Math.abs;ao.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,i=[],u=a(xo(e)),o=-1;if(n*=u,t*=u,e*=u,0>e)for(;(r=n+e*++o)>t;)i.push(r/u);else for(;(r=n+e*++o)<t;)i.push(r/u);return i},ao.map=function(n,t){var e=new c;if(n instanceof c)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)e.set(i,n[i]);else for(;++i<u;)e.set(t.call(n,r=n[i],i),r)}else for(var o in n)e.set(o,n[o]);return e};var bo="__proto__",_o="\x00";l(c,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:g,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return r?r.call(i,o):e?o.sort(e):o;for(var l,f,s,h,p=-1,g=o.length,v=u[a++],d=new c;++p<g;)(h=d.get(l=v(f=o[p])))?h.push(f):d.set(l,[f]);return t?(f=t(),s=function(e,r){f.set(e,n(t,r,a))}):(f={},s=function(e,r){f[e]=n(t,r,a)}),d.forEach(s),f}function t(n,e){if(e>=u.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,i={},u=[],o=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(ao.map,e,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},ao.set=function(n){var t=new y;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:g,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=M(n,t,t[e]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(So,"\\$&")};var So=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ko={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},No=function(n,t){return t.querySelector(n)},Eo=function(n,t){return t.querySelectorAll(n)},Ao=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ao=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(No=function(n,t){return Sizzle(n,t)[0]||null},Eo=Sizzle,Ao=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var Co=ao.selection.prototype=[];Co.select=function(n){var t,e,r,i,u=[];n=A(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var l=-1,c=r.length;++l<c;)(i=r[l])?(t.push(e=n.call(i,i.__data__,l,o)),e&&"__data__"in i&&(e.__data__=i.__data__)):t.push(null)}return E(u)},Co.selectAll=function(n){var t,e,r=[];n=C(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,l=o.length;++a<l;)(e=o[a])&&(r.push(t=co(n.call(e,e.__data__,a,i))),t.parentNode=e);return E(r)};var zo="http://www.w3.org/1999/xhtml",Lo={svg:"http://www.w3.org/2000/svg",xhtml:zo,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:Lo,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Lo.hasOwnProperty(e)?{space:Lo[e],local:n}:n}},Co.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ao.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Co.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else for(t=e.getAttribute("class");++i<r;)if(!q(n[i]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},Co.style=function(n,e,r){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Co.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},Co.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Co.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Co.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Co.insert=function(n,t){return n=j(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Co.remove=function(){return this.each(F)},Co.data=function(n,t){function e(n,e){var r,i,u,o=n.length,s=e.length,h=Math.min(o,s),p=new Array(s),g=new Array(s),v=new Array(o);if(t){var d,y=new c,m=new Array(o);for(r=-1;++r<o;)(i=n[r])&&(y.has(d=t.call(i,i.__data__,r))?v[r]=i:y.set(d,i),m[r]=d);for(r=-1;++r<s;)(i=y.get(d=t.call(e,u=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=u):g[r]=H(u),y.set(d,!0);for(r=-1;++r<o;)r in m&&y.get(m[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],u=e[r],i?(i.__data__=u,p[r]=i):g[r]=H(u);for(;s>r;++r)g[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}g.update=p,g.parentNode=p.parentNode=v.parentNode=n.parentNode,a.push(g),l.push(p),f.push(v)}var r,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++u<o;)(i=r[u])&&(n[u]=i.__data__);return n}var a=Z([]),l=E([]),f=E([]);if("function"==typeof n)for(;++u<o;)e(r=this[u],n.call(r,r.parentNode.__data__,u));else for(;++u<o;)e(r=this[u],n);return l.enter=function(){return a},l.exit=function(){return f},l},Co.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},Co.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return E(i)},Co.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Co.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Co.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Co.call=function(n){var t=co(arguments);return n.apply(t[0]=this,t),this},Co.empty=function(){return!this.node()},Co.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Co.size=function(){var n=0;return Y(this,function(){++n}),n};var qo=[];ao.selection.enter=Z,ao.selection.enter.prototype=qo,qo.append=Co.append,qo.empty=Co.empty,qo.node=Co.node,qo.call=Co.call,qo.size=Co.size,qo.select=function(n){for(var t,e,r,i,u,o=[],a=-1,l=this.length;++a<l;){r=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var c=-1,f=i.length;++c<f;)(u=i[c])?(t.push(r[c]=e=n.call(i.parentNode,u.__data__,c,a)),e.__data__=u.__data__):t.push(null)}return E(o)},qo.insert=function(n,t){return arguments.length<2&&(t=V(this)),Co.insert.call(this,n,t)},ao.select=function(t){var e;return"string"==typeof t?(e=[No(t,fo)],e.parentNode=fo.documentElement):(e=[t],e.parentNode=n(t)),E([e])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=co(Eo(n,fo)),t.parentNode=fo.documentElement):(t=co(n),t.parentNode=null),E([t])},Co.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var To=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&To.forEach(function(n){"on"+n in fo&&To.remove(n)});var Ro,Do=0;ao.mouse=function(n){return J(n,k())};var Po=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,i=0,u=t.length;u>i;++i)if((r=t[i]).identifier===e)return J(n,r)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function e(n,t,e,u,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],g|=n|e,M=r,p({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(y.on(u+d,null).on(o+d,null),m(g),p({type:"dragend"}))}var c,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=r.of(f,arguments),g=0,v=n(),d=".drag"+(null==v?"":"-"+v),y=ao.select(e(s)).on(u+d,a).on(o+d,l),m=W(s),M=t(h,v);i?(c=i.apply(f,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],p({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),i=null,u=e(b,ao.mouse,t,"mousemove","mouseup"),o=e(G,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,r,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?co(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Uo=1e-6,jo=Uo*Uo,Fo=Math.PI,Ho=2*Fo,Oo=Ho-Uo,Io=Fo/2,Yo=Fo/180,Zo=180/Fo,Vo=Math.SQRT2,Xo=2,$o=4;ao.interpolateZoom=function(n,t){var e,r,i=n[0],u=n[1],o=n[2],a=t[0],l=t[1],c=t[2],f=a-i,s=l-u,h=f*f+s*s;if(jo>h)r=Math.log(c/o)/Vo,e=function(n){return[i+n*f,u+n*s,o*Math.exp(Vo*n*r)]};else{var p=Math.sqrt(h),g=(c*c-o*o+$o*h)/(2*o*Xo*p),v=(c*c-o*o-$o*h)/(2*c*Xo*p),d=Math.log(Math.sqrt(g*g+1)-g),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-d)/Vo,e=function(n){var t=n*r,e=rn(d),a=o/(Xo*p)*(e*un(Vo*t+d)-en(d));return[i+a*f,u+a*s,o*e/rn(Vo*t+d)]}}return e.duration=1e3*r,e},ao.behavior.zoom=function(){function n(n){n.on(L,s).on(Wo+".zoom",p).on("dblclick.zoom",g).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function i(n){k.k=Math.max(A[0],Math.min(A[1],n))}function u(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},i(Math.pow(2,o)),u(d=e,r),t=ao.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function f(n){--z||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),c(o)}function r(){s.on(q,null).on(T,null),p(a),f(o)}var i=this,o=D.of(i,arguments),a=0,s=ao.select(t(i)).on(q,n).on(T,r),h=e(ao.mouse(i)),p=W(i);Il.call(i),l(o)}function h(){function n(){var n=ao.touches(g);return p=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,r).on(b,a),_.push(t);for(var e=ao.event.changedTouches,i=0,u=e.length;u>i;++i)d[e[i].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var f=l[0];o(g,f,d[f.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var f=l[0],s=l[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function r(){var n,t,e,r,o=ao.touches(g);Il.call(g);for(var a=0,l=o.length;l>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var f=(f=e[0]-n[0])*f+(f=e[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],i(s*p)}M=null,u(n,t),c(v)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var i in d)return void n()}ao.selectAll(_).on(m,null),w.on(L,s).on(R,h),N(),f(v)}var p,g=this,v=D.of(g,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,b="touchend"+m,_=[],w=ao.select(g),N=W(g);t(),l(v),w.on(L,null).on(R,t)}function p(){var n=D.of(this,arguments);m?clearTimeout(m):(Il.call(this),v=e(d=y||ao.mouse(this)),l(n)),m=setTimeout(function(){m=null,f(n)},50),S(),i(Math.pow(2,.002*Bo())*k.k),u(d,v),c(n)}function g(){var n=ao.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,y,m,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Jo,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return Wo||(Wo="onwheel"in fo?(Bo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Bo=function(){return ao.event.wheelDelta},"mousewheel"):(Bo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Hl?ao.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],i=d?d[0]:e/2,u=d?d[1]:r/2,o=ao.interpolateZoom([(i-k.x)/k.k,(u-k.y)/k.k,e/k.k],[(i-t.x)/t.k,(u-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:i-r[0]*a,y:u-r[1]*a,k:a},c(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=k,l(n),c(n),f(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},i(+t),a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Jo:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ao.rebind(n,D,"on")};var Bo,Wo,Jo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=ln;var Go=ln.prototype=new an;Go.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Go.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Go.rgb=function(){return cn(this.h,this.s,this.l)},ao.hcl=fn;var Ko=fn.prototype=new an;Ko.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Ko.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Ko.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,na=.95047,ta=1,ea=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ia=mn.prototype=new an;ia.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mn(i,i,i)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ia.hsl=function(){return wn(this.r,this.g,this.b)},ia.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ua=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ua.forEach(function(n,t){ua.set(n,Mn(t))}),ao.functor=En,ao.xhr=An(m),ao.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var o=Cn(n,t,null==e?r:i(e),u);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:i(n)):e},o}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var r=n.charCodeAt(e+1);return 13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;c>f;){var r=n.charCodeAt(f++),a=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(r!==l)continue;return n.slice(t,f-a)}return n.slice(t)}for(var r,i,u={},o={},a=[],c=n.length,f=0,s=0;(r=e())!==o;){for(var h=[];r!==u&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,s++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new y,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(u).join("\n")},e},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv("	","text/tab-separated-values");var oa,aa,la,ca,fa=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){qn.apply(this,arguments)},ao.timer.flush=function(){Rn(),Dn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var sa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(Un);ao.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),sa[8+e/3]};var ha=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pa=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ga=ao.time={},va=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){da.setUTCDate.apply(this._,arguments)},setDay:function(){da.setUTCDay.apply(this._,arguments)},setFullYear:function(){da.setUTCFullYear.apply(this._,arguments)},setHours:function(){da.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){da.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){da.setUTCMinutes.apply(this._,arguments)},setMonth:function(){da.setUTCMonth.apply(this._,arguments)},setSeconds:function(){da.setUTCSeconds.apply(this._,arguments)},setTime:function(){da.setTime.apply(this._,arguments)}};var da=Date.prototype;ga.year=On(function(n){return n=ga.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ga.years=ga.year.range,ga.years.utc=ga.year.utc.range,ga.day=On(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ga.days=ga.day.range,ga.days.utc=ga.day.utc.range,ga.dayOfYear=function(n){var t=ga.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ga[n]=On(function(n){return(n=ga.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ga[n+"s"]=e.range,ga[n+"s"].utc=e.utc.range,ga[n+"OfYear"]=function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)}}),ga.week=ga.sunday,ga.weeks=ga.sunday.range,ga.weeks.utc=ga.sunday.utc.range,ga.weekOfYear=ga.sundayOfYear;var ya={"-":"",_:" ",0:"0"},ma=/^\s*\d+/,Ma=/^%/;ao.locale=function(n){return{numberFormat:jn(n),timeFormat:Yn(n)}};var xa=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=xa.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,ba),st(ba.s,this.s,this),this.s?this.t+=ba.t:this.s=ba.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var ba=new ft;ao.geo.stream=function(n,t){n&&_a.hasOwnProperty(n.type)?_a[n.type](n,t):ht(n,t)};var _a={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,i=e.length;++r<i;)ht(e[r].geometry,t)}},wa={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)pt(e[r],t,0)},Polygon:function(n,t){gt(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)gt(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,i=e.length;++r<i;)ht(e[r],t)}};ao.geo.area=function(n){return Sa=0,ao.geo.stream(n,Na),Sa};var Sa,ka=new ft,Na={sphere:function(){Sa+=4*Fo},point:b,lineStart:b,lineEnd:b,polygonStart:function(){ka.reset(),Na.lineStart=vt},polygonEnd:function(){var n=2*ka;Sa+=0>n?4*Fo+n:n,Na.lineStart=Na.lineEnd=Na.point=b}};ao.geo.bounds=function(){function n(n,t){M.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,e){var r=dt([t*Yo,e*Yo]);if(y){var i=mt(y,r),u=[i[1],-i[0],0],o=mt(u,i);bt(o),o=_t(o);var l=t-g,c=l>0?1:-1,v=o[0]*Zo*c,d=xo(l)>180;if(d^(v>c*g&&c*t>v)){var m=o[1]*Zo;m>p&&(p=m)}else if(v=(v+360)%360-180,d^(v>c*g&&c*t>v)){var m=-o[1]*Zo;s>m&&(s=m)}else s>e&&(s=e),e>p&&(p=e);d?g>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>g?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,e);y=r,g=t}function e(){b.point=t}function r(){x[0]=f,x[1]=h,b.point=n,y=null}function i(n,e){if(y){var r=n-g;m+=xo(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Na.point(n,e),t(n,e)}function u(){Na.lineStart()}function o(){i(v,d),Na.lineEnd(),xo(m)>Uo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function l(n,t){return n[0]-t[0]}function c(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,g,v,d,y,m,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=u,b.lineEnd=o,m=0,Na.polygonStart()},polygonEnd:function(){Na.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>ka?(f=-(h=180),s=-(p=90)):m>Uo?p=90:-Uo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),M=[],ao.geo.stream(n,b);var t=M.length;if(t){M.sort(l);for(var e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],c(e[0],i)||c(e[1],i)?(a(i[0],e[1])>a(i[0],i[1])&&(i[1]=e[1]),a(e[0],i[1])>a(i[0],i[1])&&(i[0]=e[0])):u.push(i=e);for(var o,e,g=-(1/0),t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(o=a(i[1],e[0]))>g&&(g=o,f=e[0],h=i[1])}return M=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Ea=Aa=Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,ja);var t=Da,e=Pa,r=Ua,i=t*t+e*e+r*r;return jo>i&&(t=qa,e=Ta,r=Ra,Uo>Aa&&(t=Ca,e=za,r=La),i=t*t+e*e+r*r,jo>i)?[NaN,NaN]:[Math.atan2(e,t)*Zo,tn(r/Math.sqrt(i))*Zo]};var Ea,Aa,Ca,za,La,qa,Ta,Ra,Da,Pa,Ua,ja={sphere:b,point:St,lineStart:Nt,lineEnd:Et,polygonStart:function(){ja.lineStart=At},polygonEnd:function(){ja.lineStart=Nt}},Fa=Rt(zt,jt,Ht,[-Fo,-Fo/2]),Ha=1e9;ao.geo.clipExtent=function(){var n,t,e,r,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Zt(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Vt(Xt)}).raw=Xt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,e(u,o),t||(r(u,o),t)||i(u,o),t}var t,e,r,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?o:i>=.166&&.234>i&&r>=-.214&&-.115>r?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var c=u.scale(),f=+t[0],s=+t[1];return e=u.translate(t).clipExtent([[f-.455*c,s-.238*c],[f+.455*c,s+.238*c]]).stream(l).point,r=o.translate([f-.307*c,s+.201*c]).clipExtent([[f-.425*c+Uo,s+.12*c+Uo],[f-.214*c-Uo,s+.234*c-Uo]]).stream(l).point,i=a.translate([f-.205*c,s+.212*c]).clipExtent([[f-.214*c+Uo,s+.166*c+Uo],[f-.115*c-Uo,s+.234*c-Uo]]).stream(l).point,n},n.scale(1070)};var Oa,Ia,Ya,Za,Va,Xa,$a={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Ia=0,$a.lineStart=$t},polygonEnd:function(){$a.lineStart=$a.lineEnd=$a.point=b,Oa+=xo(Ia/2)}},Ba={point:Bt,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Wa={point:Gt,lineStart:Kt,lineEnd:Qt,polygonStart:function(){Wa.lineStart=ne},polygonEnd:function(){Wa.point=Gt,Wa.lineStart=Kt,Wa.lineEnd=Qt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var e,r,i,u,o,a=4.5;return n.area=function(n){return Oa=0,ao.geo.stream(n,i($a)),Oa},n.centroid=function(n){return Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,i(Wa)),Ua?[Da/Ua,Pa/Ua]:Ra?[qa/Ra,Ta/Ra]:La?[Ca/La,za/La]:[NaN,NaN]},n.bounds=function(n){return Va=Xa=-(Ya=Za=1/0),ao.geo.stream(n,i(Ba)),[[Ya,Za],[Va,Xa]]},n.projection=function(n){return arguments.length?(i=(e=n)?n.stream||re(n):m,t()):e},n.context=function(n){return arguments.length?(u=null==(r=n)?new Wt:new te(n),"function"!=typeof a&&u.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var e=new ie(t);for(var r in n)e[r]=n[r];return e}}},ie.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=oe,ao.geo.projectionMutator=ae,(ao.geo.equirectangular=function(){return oe(ce)}).raw=ce.invert=ce,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t}return n=se(n[0]%360*Yo,n[1]*Yo,n.length>2?n[2]*Yo:0),t.invert=function(t){return t=n.invert(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t},t},fe.invert=ce,ao.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=se(-n[0]*Yo,-n[1]*Yo,0).invert,i=[];return e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=Zo,n[1]*=Zo}}),{type:"Polygon",coordinates:[i]}}var t,e,r=[0,0],i=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=ve((t=+r)*Yo,i*Yo),n):t},n.precision=function(r){return arguments.length?(e=ve(t*Yo,(i=+r)*Yo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Yo,i=n[1]*Yo,u=t[1]*Yo,o=Math.sin(r),a=Math.cos(r),l=Math.sin(i),c=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((e=s*o)*e+(e=c*f-l*s*a)*e),l*f+c*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(c/y)*y,l,y).map(p)).concat(ao.range(Math.ceil(r/g)*g,e,g).filter(function(n){return xo(n%d)>Uo}).map(f)).concat(ao.range(Math.ceil(a/v)*v,o,v).filter(function(n){return xo(n%y)>Uo}).map(s))}var e,r,i,u,o,a,l,c,f,s,h,p,g=10,v=g,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(l).slice(1),h(i).reverse().slice(1),p(c).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],c=+t[0][1],l=+t[1][1],u>i&&(t=u,u=i,i=t),c>l&&(t=c,c=l,l=t),n.precision(m)):[[u,c],[i,l]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(g=+t[0],v=+t[1],n):[g,v]},n.precision=function(t){return arguments.length?(m=+t,f=ye(a,o,90),s=me(r,e,m),h=ye(c,l,90),p=me(u,i,m),n):m},n.majorExtent([[-180,-90+Uo],[180,90-Uo]]).minorExtent([[-180,-80-Uo],[180,80+Uo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var t,e,r=Me,i=xe;return n.distance=function(){return ao.geo.distance(t||r.apply(this,arguments),e||i.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(i=t,e="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return be(n[0]*Yo,n[1]*Yo,t[0]*Yo,t[1]*Yo)},ao.geo.length=function(n){return Ja=0,ao.geo.stream(n,Ga),Ja};var Ja,Ga={sphere:b,point:b,lineStart:_e,lineEnd:b,polygonStart:b,polygonEnd:b},Ka=we(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return oe(Ka)}).raw=Ka;var Qa=we(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return oe(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Vt(Se)}).raw=Se,(ao.geo.conicEquidistant=function(){return Vt(ke)}).raw=ke;var nl=we(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return oe(nl)}).raw=nl,Ne.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Io]},(ao.geo.mercator=function(){return Ee(Ne)}).raw=Ne;var tl=we(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return oe(tl)}).raw=tl;var el=we(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return oe(el)}).raw=el,Ae.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Io]},(ao.geo.transverseMercator=function(){var n=Ee(Ae),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Ae,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=En(e),u=En(r),o=n.length,a=[],l=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(qe),t=0;o>t;t++)l.push([a[t][0],-a[t][1]]);var c=Le(a),f=Le(l),s=f[0]===c[0],h=f[f.length-1]===c[c.length-1],p=[];for(t=c.length-1;t>=0;--t)p.push(n[a[c[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var e=Ce,r=ze;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ao.geom.polygon=function(n){return ko(n,rl),n};var rl=ao.geom.polygon.prototype=[];rl.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],i=0;++t<e;)n=r,r=this[t],i+=n[1]*r[0]-n[0]*r[1];return.5*i},rl.centroid=function(n){var t,e,r=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++r<i;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[u*n,o*n]},rl.clip=function(n){for(var t,e,r,i,u,o,a=De(n),l=-1,c=this.length-De(this),f=this[c-1];++l<c;){for(t=n.slice(),n.length=0,i=this[l],u=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Te(o,f,i)?(Te(u,f,i)||n.push(Re(u,o,f,i)),n.push(o)):Te(u,f,i)&&n.push(Re(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var il,ul,ol,al,ll,cl=[],fl=[];Ye.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Ve),t.length},tr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(n,t){var e,r,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=or(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.R&&(ir(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ur(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.L&&(ur(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ir(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,i=n.U,u=n.L,o=n.R;if(e=u?o?or(o):u:o,i?i.L===n?i.L=e:i.R=e:this._=e,u&&o?(r=e.C,e.C=n.C,e.L=u,u.U=e,e!==o?(i=e.U,e.U=n.U,n=e.R,i.L=n,e.R=o,o.U=e):(e.U=i,i=e,n=e.R)):(r=n.C,n=e),n&&(n.U=i),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ir(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ur(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ir(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ur(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ir(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ur(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ar(e(n),a).cells.forEach(function(e,a){var l=e.edges,c=e.site,f=t[a]=l.length?l.map(function(n){var t=n.start();return[t.x,t.y]}):c.x>=r&&c.x<=u&&c.y>=i&&c.y<=o?[[r,o],[u,o],[u,i],[r,i]]:[];f.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Uo)*Uo,y:Math.round(o(n,t)/Uo)*Uo,i:t}})}var r=Ce,i=ze,u=r,o=i,a=sl;return n?t(n):(t.links=function(n){return ar(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ar(e(n)).cells.forEach(function(e,r){for(var i,u,o=e.site,a=e.edges.sort(Ve),l=-1,c=a.length,f=a[c-1].edge,s=f.l===o?f.r:f.l;++l<c;)i=f,u=s,f=a[l].edge,s=f.l===o?f.r:f.l,r<u.i&&r<s.i&&cr(o,u,s)<0&&t.push([n[r],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=En(r=n),t):r},t.y=function(n){return arguments.length?(o=En(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?sl:n,t):a===sl?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===sl?null:a&&a[1]},t)};var sl=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,e,r,i){function u(n){function u(n,t,e,r,i,u,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var l=n.x,f=n.y;if(null!=l)if(xo(l-e)+xo(f-r)<.01)c(n,t,e,r,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,c(n,s,l,f,i,u,o,a),c(n,t,e,r,i,u,o,a)}else n.x=e,n.y=r,n.point=t}else c(n,t,e,r,i,u,o,a)}function c(n,t,e,r,i,o,a,l){var c=.5*(i+a),f=.5*(o+l),s=e>=c,h=r>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=hr()),s?i=c:a=c,h?o=f:l=f,u(n,t,e,r,i,o,a,l)}var f,s,h,p,g,v,d,y,m,M=En(a),x=En(l);if(null!=t)v=t,d=e,y=r,m=i;else if(y=m=-(v=d=1/0),s=[],h=[],g=n.length,o)for(p=0;g>p;++p)f=n[p],f.x<v&&(v=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;g>p;++p){var b=+M(f=n[p],p),_=+x(f,p);v>b&&(v=b),d>_&&(d=_),b>y&&(y=b),_>m&&(m=_),s.push(b),h.push(_)}var w=y-v,S=m-d;w>S?m=d+w:y=v+S;var k=hr();if(k.add=function(n){u(k,n,+M(n,++p),+x(n,p),v,d,y,m)},k.visit=function(n){pr(n,k,v,d,y,m)},k.find=function(n){return gr(k,n[0],n[1],v,d,y,m)},p=-1,null==t){for(;++p<g;)u(k,n[p],s[p],h[p],v,d,y,m);--p}else n.forEach(k.add);return s=h=n=f=null,k}var o,a=Ce,l=ze;return(o=arguments.length)?(a=fr,l=sr,3===o&&(i=e,r=t,e=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(l=n,u):l},u.extent=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,e],[r,i]]},u.size=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=e=0,r=+n[0],i=+n[1]),u):null==t?null:[r-t,i-e]},u)},ao.interpolateRgb=vr,ao.interpolateObject=dr,ao.interpolateNumber=yr,ao.interpolateString=mr;var hl=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,pl=new RegExp(hl.source,"g");ao.interpolate=Mr,ao.interpolators=[function(n,t){var e=typeof t;return("string"===e?ua.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?vr:mr:t instanceof an?vr:Array.isArray(t)?xr:"object"===e&&isNaN(t)?dr:yr)(n,t)}],ao.interpolateArray=xr;var gl=function(){return m},vl=ao.map({linear:gl,poly:Er,quad:function(){return Sr},cubic:function(){return kr},sin:function(){return Ar},exp:function(){return Cr},circle:function(){return zr},elastic:Lr,back:qr,bounce:function(){return Tr}}),dl=ao.map({"in":m,out:_r,"in-out":wr,"out-in":function(n){return wr(_r(n))}});ao.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=vl.get(e)||gl,r=dl.get(r)||m,br(r(e.apply(null,lo.call(arguments,1))))},ao.interpolateHcl=Rr,ao.interpolateHsl=Dr,ao.interpolateLab=Pr,ao.interpolateRound=Ur,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new jr(e?e.matrix:yl)})(n)},jr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var yl={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=$r,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Jr(n[e]));return t}},ao.layout.chord=function(){function n(){var n,c,s,h,p,g={},v=[],d=ao.range(u),y=[];for(e=[],r=[],n=0,h=-1;++h<u;){for(c=0,p=-1;++p<u;)c+=i[h][p];v.push(c),y.push(ao.range(u)),n+=c}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&y.forEach(function(n,t){n.sort(function(n,e){return a(i[t][n],i[t][e])})}),n=(Ho-f*u)/n,c=0,h=-1;++h<u;){for(s=c,p=-1;++p<u;){var m=d[h],M=y[m][p],x=i[m][M],b=c,_=c+=x*n;g[m+"-"+M]={index:m,subindex:M,startAngle:b,endAngle:_,value:x}}r[m]={index:m,startAngle:s,endAngle:c,value:v[m]},c+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=g[h+"-"+p],S=g[p+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}l&&t()}function t(){e.sort(function(n,t){return l((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,i,u,o,a,l,c={},f=0;return c.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,e=r=null,c):i},c.padding=function(n){return arguments.length?(f=n,e=r=null,c):f},c.sortGroups=function(n){return arguments.length?(o=n,e=r=null,c):o},c.sortSubgroups=function(n){return arguments.length?(a=n,e=null,c):a},c.sortChords=function(n){return arguments.length?(l=n,e&&t(),c):l},c.chords=function(){return e||n(),e},c.groups=function(){return r||n(),r},c},ao.layout.force=function(){function n(n){return function(t,e,r,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-e,l=u*u+o*o;if(l>a*a/y){if(v>l){var c=t.charge/l;n.px-=u*c,n.py-=o*c}return!0}if(t.point&&l&&v>l){var c=t.pointCharge/l;n.px-=u*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,l.resume()}var e,r,i,u,o,a,l={},c=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=ml,p=Ml,g=-30,v=xl,d=.1,y=.64,M=[],x=[];return l.tick=function(){if((i*=.99)<.005)return e=null,c.end({type:"end",alpha:i=0}),!0;var t,r,l,h,p,v,y,m,b,_=M.length,w=x.length;for(r=0;w>r;++r)l=x[r],h=l.source,p=l.target,m=p.x-h.x,b=p.y-h.y,(v=m*m+b*b)&&(v=i*o[r]*((v=Math.sqrt(v))-u[r])/v,m*=v,b*=v,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*y,h.x+=m*(y=1-y),h.y+=b*y);if((y=i*d)&&(m=f[0]/2,b=f[1]/2,r=-1,y))for(;++r<_;)l=M[r],l.x+=(m-l.x)*y,l.y+=(b-l.y)*y;if(g)for(ri(t=ao.geom.quadtree(M),i,a),r=-1;++r<_;)(l=M[r]).fixed||t.visit(n(l));for(r=-1;++r<_;)l=M[r],l.fixed?(l.x=l.px,l.y=l.py):(l.x-=(l.px-(l.px=l.x))*s,l.y-=(l.py-(l.py=l.y))*s);c.tick({type:"tick",alpha:i})},l.nodes=function(n){return arguments.length?(M=n,l):M},l.links=function(n){return arguments.length?(x=n,l):x},l.size=function(n){return arguments.length?(f=n,l):f},l.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,l):h},l.distance=l.linkDistance,l.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,l):p},l.friction=function(n){return arguments.length?(s=+n,l):s},l.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,l):g},l.chargeDistance=function(n){return arguments.length?(v=n*n,l):Math.sqrt(v)},l.gravity=function(n){return arguments.length?(d=+n,l):d},l.theta=function(n){return arguments.length?(y=n*n,l):Math.sqrt(y)},l.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(e.c=null,e.t=NaN,e=null,c.end({type:"end",alpha:i=0})):n>0&&(c.start({type:"start",alpha:i=n}),e=qn(l.tick)),l):i},l.start=function(){function n(n,r){if(!e){for(e=new Array(i),l=0;i>l;++l)e[l]=[];for(l=0;c>l;++l){var u=x[l];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var o,a=e[t],l=-1,f=a.length;++l<f;)if(!isNaN(o=a[l][n]))return o;return Math.random()*r}var t,e,r,i=M.length,c=x.length,s=f[0],v=f[1];for(t=0;i>t;++t)(r=M[t]).index=t,r.weight=0;for(t=0;c>t;++t)r=x[t],"number"==typeof r.source&&(r.source=M[r.source]),"number"==typeof r.target&&(r.target=M[r.target]),++r.source.weight,++r.target.weight;for(t=0;i>t;++t)r=M[t],isNaN(r.x)&&(r.x=n("x",s)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof h)for(t=0;c>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;c>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;c>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;c>t;++t)o[t]=p;if(a=[],"function"==typeof g)for(t=0;i>t;++t)a[t]=+g.call(this,M[t],t);else for(t=0;i>t;++t)a[t]=g;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){return r||(r=ao.behavior.drag().origin(m).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ei).call(r):r},ao.rebind(l,c,"on")};var ml=20,Ml=1,xl=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(c=e.call(n,u,u.depth))&&(l=c.length)){for(var l,c,f;--l>=0;)o.push(f=c[l]),f.parent=u,f.depth=u.depth+1;r&&(u.value=0),u.children=c}else r&&(u.value=+r.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var e,i;t&&(e=n.children)&&e.sort(t),r&&(i=n.parent)&&(i.value+=n.value)}),a}var t=ci,e=ai,r=li;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,e,r,i){var u=t.children;if(t.x=e,t.y=t.depth*i,t.dx=r,t.dy=i,u&&(o=u.length)){var o,a,l,c=-1;for(r=t.value?r/t.value:0;++c<o;)n(a=u[c],e,l=a.value*r,i),e+=l}}function t(n){var e=n.children,r=0;if(e&&(i=e.length))for(var i,u=-1;++u<i;)r=Math.max(r,t(e[u]));return 1+r}function e(e,u){var o=r.call(this,e,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var r=ao.layout.hierarchy(),i=[1,1];return e.size=function(n){return arguments.length?(i=n,e):i},ii(e,r)},ao.layout.pie=function(){function n(o){var a,l=o.length,c=o.map(function(e,r){return+t.call(n,e,r)}),f=+("function"==typeof r?r.apply(this,arguments):r),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/l,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),g=ao.sum(c),v=g?(s-l*p)/g:0,d=ao.range(l),y=[];return null!=e&&d.sort(e===bl?function(n,t){return c[t]-c[n]}:function(n,t){return e(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=c[n],startAngle:f,endAngle:f+=a*v+p,padAngle:h}}),y}var t=Number,e=bl,r=0,i=Ho,u=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var bl={};ao.layout.stack=function(){function n(a,l){if(!(h=a.length))return a;var c=a.map(function(e,r){return t.call(n,e,r)}),f=c.map(function(t){return t.map(function(t,e){return[u.call(n,t,e),o.call(n,t,e)]})}),s=e.call(n,f,l);c=ao.permute(c,s),f=ao.permute(f,s);var h,p,g,v,d=r.call(n,f,l),y=c[0].length;for(g=0;y>g;++g)for(i.call(n,c[0][g],v=d[g],f[0][g][1]),p=1;h>p;++p)i.call(n,c[p][g],v+=f[p-1][g][1],f[p][g][1]);return a}var t=m,e=gi,r=vi,i=pi,u=si,o=hi;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:_l.get(t)||gi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:wl.get(t)||vi,n):r},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var _l=ao.map({"inside-out":function(n){var t,e,r=n.length,i=n.map(di),u=n.map(yi),o=ao.range(r).sort(function(n,t){return i[n]-i[t]}),a=0,l=0,c=[],f=[];for(t=0;r>t;++t)e=o[t],l>a?(a+=u[e],c.push(e)):(l+=u[e],f.push(e));return f.reverse().concat(c)},reverse:function(n){return ao.range(n.length).reverse()},"default":gi}),wl=ao.map({silhouette:function(n){var t,e,r,i=n.length,u=n[0].length,o=[],a=0,l=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;u>e;++e)l[e]=(a-o[e])/2;return l},wiggle:function(n){var t,e,r,i,u,o,a,l,c,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=l=c=0,e=1;h>e;++e){for(t=0,i=0;f>t;++t)i+=n[t][e][1];for(t=0,u=0,a=s[e][0]-s[e-1][0];f>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;u+=o*n[t][e][1]}p[e]=l-=i?u/i*a:0,c>l&&(c=l)}for(e=0;h>e;++e)p[e]-=c;return p},expand:function(n){var t,e,r,i=n.length,u=n[0].length,o=1/i,a=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else for(t=0;i>t;t++)n[t][e][1]=o}for(e=0;u>e;++e)a[e]=0;return a},zero:vi});ao.layout.histogram=function(){function n(n,u){for(var o,a,l=[],c=n.map(e,this),f=r.call(this,c,u),s=i.call(this,f,c,u),u=-1,h=c.length,p=s.length-1,g=t?1:1/h;++u<p;)o=l[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=c[u],a>=f[0]&&a<=f[1]&&(o=l[ao.bisect(s,a,1,p)-1],o.y+=g,o.push(n[u]));return l}var t=!0,e=Number,r=bi,i=Mi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=En(t),n):r},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:En(t),n):i},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ao.layout.pack=function(){function n(n,u){var o=e.call(this,n,u),a=o[0],l=i[0],c=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ni),r){var s=r*(t?1:Math.max(2*a.r/l,2*a.r/c))/2;oi(a,function(n){n.r+=s}),oi(a,Ni),oi(a,function(n){n.r-=s})}return Ci(a,l/2,c/2,t?1:1/Math.max(2*a.r/l,2*a.r/c)),o}var t,e=ao.layout.hierarchy().sort(_i),r=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},ii(n,e)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,e),h.parent.m=-h.z,ui(h,r),c)ui(s,u);else{var p=s,g=s,v=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>g.x&&(g=n),n.depth>v.depth&&(v=n)});var d=a(p,g)/2-p.x,y=l[0]/(g.x+a(g,p)/2+d),m=l[1]/(v.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)r.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Di(n);var u=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-u):n.z=u}else r&&(n.z=r.z+a(n._,r._));n.parent.A=i(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,e){if(t){for(var r,i=n,u=n,o=t,l=i.parent.children[0],c=i.m,f=u.m,s=o.m,h=l.m;o=Ti(o),i=qi(i),o&&i;)l=qi(l),u=Ti(u),u.a=n,r=o.z+s-i.z-c+a(o._,i._),r>0&&(Ri(Pi(o,n,e),n,r),c+=r,f+=r),s+=o.m,c+=i.m,h+=l.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!qi(l)&&(l.t=i,l.m+=c-h,e=n)}return e}function u(n){n.x*=l[0],n.y=n.depth*l[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=Li,l=[1,1],c=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(c=null==(l=t)?u:null,n):c?null:l},n.nodeSize=function(t){return arguments.length?(c=null==(l=t)?null:u,n):c?l:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),l=a[0],c=0;oi(l,function(n){var t=n.children;t&&t.length?(n.x=ji(t),n.y=Ui(t)):(n.x=o?c+=e(n,o):0,n.y=0,o=n)});var f=Fi(l),s=Hi(l),h=f.x-e(f,s)/2,p=s.x+e(s,f)/2;return oi(l,i?function(n){n.x=(n.x-l.x)*r[0],n.y=(l.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(p-h)*r[0],n.y=(1-(l.y?n.y/l.y:1))*r[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),e=Li,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var e,r,i=-1,u=n.length;++i<u;)r=(e=n[i]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var u=e.children;if(u&&u.length){var o,a,l,c=s(e),f=[],h=u.slice(),g=1/0,v="slice"===p?c.dx:"dice"===p?c.dy:"slice-dice"===p?1&e.depth?c.dy:c.dx:Math.min(c.dx,c.dy);for(n(h,c.dx*c.dy/e.value),f.area=0;(l=h.length)>0;)f.push(o=h[l-1]),f.area+=o.area,"squarify"!==p||(a=r(f,v))<=g?(h.pop(),g=a):(f.area-=f.pop().area,i(f,v,c,!1),v=Math.min(c.dx,c.dy),f.length=f.area=0,g=1/0);f.length&&(i(f,v,c,!0),f.length=f.area=0),u.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var u,o=s(t),a=r.slice(),l=[];for(n(a,o.dx*o.dy/t.value),l.area=0;u=a.pop();)l.push(u),l.area+=u.area,null!=u.z&&(i(l,u.z?o.dx:o.dy,o,!a.length),l.length=l.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(u>e&&(u=e),e>i&&(i=e));return r*=r,t*=t,r?Math.max(t*i*g/r,r/(t*u*g)):1/0}function i(n,t,e,r){var i,u=-1,o=n.length,a=e.x,c=e.y,f=t?l(n.area/t):0;
+if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<o;)i=n[u],i.x=a,i.y=c,i.dy=f,a+=i.dx=Math.min(e.x+e.dx-a,f?l(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-a,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<o;)i=n[u],i.x=a,i.y=c,i.dx=f,c+=i.dy=Math.min(e.y+e.dy-c,f?l(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-c,e.x+=f,e.dx-=f}}function u(r){var i=o||a(r),u=i[0];return u.x=u.y=0,u.value?(u.dx=c[0],u.dy=c[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?e:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),l=Math.round,c=[1,1],f=null,s=Oi,h=!1,p="squarify",g=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(c=n,u):c},u.padding=function(n){function t(t){var e=n.call(u,t,t.depth);return null==e?Oi(t):Ii(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Ii(t,n)}if(!arguments.length)return f;var r;return s=null==(f=n)?Oi:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,u},u.round=function(n){return arguments.length?(l=n?Math.round:Number,u):l!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(g=n,u):g},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ao.scale={};var Sl={floor:m,ceil:m};ao.scale.linear=function(){return Wi([0,1],[0,1],Mr,!1)};var kl={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return ru(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Nl=ao.format(".0e"),El={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Al)},ao.scale.category20=function(){return ao.scale.ordinal().range(Cl)},ao.scale.category20b=function(){return ao.scale.ordinal().range(zl)},ao.scale.category20c=function(){return ao.scale.ordinal().range(Ll)};var Al=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Cl=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),zl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),Ll=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return lu(0,1,[0,1])},ao.scale.threshold=function(){return cu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),c=Math.max(0,+r.apply(this,arguments)),f=o.apply(this,arguments)-Io,s=a.apply(this,arguments)-Io,h=Math.abs(s-f),p=f>s?0:1;if(n>c&&(g=c,c=n,n=g),h>=Oo)return t(c,p)+(n?t(n,1-p):"")+"Z";var g,v,d,y,m,M,x,b,_,w,S,k,N=0,E=0,A=[];if((y=(+l.apply(this,arguments)||0)/2)&&(d=u===ql?Math.sqrt(n*n+c*c):+u.apply(this,arguments),p||(E*=-1),c&&(E=tn(d/c*Math.sin(y))),n&&(N=tn(d/n*Math.sin(y)))),c){m=c*Math.cos(f+E),M=c*Math.sin(f+E),x=c*Math.cos(s-E),b=c*Math.sin(s-E);var C=Math.abs(s-f-2*E)<=Fo?0:1;if(E&&yu(m,M,x,b)===p^C){var z=(f+s)/2;m=c*Math.cos(z),M=c*Math.sin(z),x=b=null}}else m=M=0;if(n){_=n*Math.cos(s-N),w=n*Math.sin(s-N),S=n*Math.cos(f+N),k=n*Math.sin(f+N);var L=Math.abs(f-s+2*N)<=Fo?0:1;if(N&&yu(_,w,S,k)===1-p^L){var q=(f+s)/2;_=n*Math.cos(q),w=n*Math.sin(q),S=k=null}}else _=w=0;if(h>Uo&&(g=Math.min(Math.abs(c-n)/2,+i.apply(this,arguments)))>.001){v=c>n^p?0:1;var T=g,R=g;if(Fo>h){var D=null==S?[_,w]:null==x?[m,M]:Re([m,M],[S,k],[x,b],[_,w]),P=m-D[0],U=M-D[1],j=x-D[0],F=b-D[1],H=1/Math.sin(Math.acos((P*j+U*F)/(Math.sqrt(P*P+U*U)*Math.sqrt(j*j+F*F)))/2),O=Math.sqrt(D[0]*D[0]+D[1]*D[1]);R=Math.min(g,(n-O)/(H-1)),T=Math.min(g,(c-O)/(H+1))}if(null!=x){var I=mu(null==S?[_,w]:[S,k],[m,M],c,T,p),Y=mu([x,b],[_,w],c,T,p);g===T?A.push("M",I[0],"A",T,",",T," 0 0,",v," ",I[1],"A",c,",",c," 0 ",1-p^yu(I[1][0],I[1][1],Y[1][0],Y[1][1]),",",p," ",Y[1],"A",T,",",T," 0 0,",v," ",Y[0]):A.push("M",I[0],"A",T,",",T," 0 1,",v," ",Y[0])}else A.push("M",m,",",M);if(null!=S){var Z=mu([m,M],[S,k],n,-R,p),V=mu([_,w],null==x?[m,M]:[x,b],n,-R,p);g===R?A.push("L",V[0],"A",R,",",R," 0 0,",v," ",V[1],"A",n,",",n," 0 ",p^yu(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-p," ",Z[1],"A",R,",",R," 0 0,",v," ",Z[0]):A.push("L",V[0],"A",R,",",R," 0 0,",v," ",Z[0])}else A.push("L",_,",",w)}else A.push("M",m,",",M),null!=x&&A.push("A",c,",",c," 0 ",C,",",p," ",x,",",b),A.push("L",_,",",w),null!=S&&A.push("A",n,",",n," 0 ",L,",",1-p," ",S,",",k);return A.push("Z"),A.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=hu,r=pu,i=su,u=ql,o=gu,a=vu,l=du;return n.innerRadius=function(t){return arguments.length?(e=En(t),n):e},n.outerRadius=function(t){return arguments.length?(r=En(t),n):r},n.cornerRadius=function(t){return arguments.length?(i=En(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==ql?ql:En(t),n):u},n.startAngle=function(t){return arguments.length?(o=En(t),n):o},n.endAngle=function(t){return arguments.length?(a=En(t),n):a},n.padAngle=function(t){return arguments.length?(l=En(t),n):l},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Io;return[Math.cos(t)*n,Math.sin(t)*n]},n};var ql="auto";ao.svg.line=function(){return Mu(m)};var Tl=ao.map({linear:xu,"linear-closed":bu,step:_u,"step-before":wu,"step-after":Su,basis:zu,"basis-open":Lu,"basis-closed":qu,bundle:Tu,cardinal:Eu,"cardinal-open":ku,"cardinal-closed":Nu,monotone:Fu});Tl.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Rl=[0,2/3,1/3,0],Dl=[0,1/3,2/3,0],Pl=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=Mu(Hu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=Su,Su.reverse=wu,ao.svg.area=function(){return Ou(m)},ao.svg.area.radial=function(){var n=Ou(Hu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var l=t(this,u,n,a),c=t(this,o,n,a);return"M"+l.p0+r(l.r,l.p1,l.a1-l.a0)+(e(l,c)?i(l.r,l.p1,l.r,l.p0):i(l.r,l.p1,c.r,c.p0)+r(c.r,c.p1,c.a1-c.a0)+i(c.r,c.p1,l.r,l.p0))+"Z"}function t(n,t,e,r){var i=t.call(n,e,r),u=a.call(n,i,r),o=l.call(n,i,r)-Io,f=c.call(n,i,r)-Io;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Fo)+",1 "+t}function i(n,t,e,r){return"Q 0,0 "+r}var u=Me,o=xe,a=Iu,l=gu,c=vu;return n.radius=function(t){return arguments.length?(a=En(t),n):a},n.source=function(t){return arguments.length?(u=En(t),n):u},n.target=function(t){return arguments.length?(o=En(t),n):o},n.startAngle=function(t){return arguments.length?(l=En(t),n):l},n.endAngle=function(t){return arguments.length?(c=En(t),n):c},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=e.call(this,n,i),a=(u.y+o.y)/2,l=[u,{x:u.x,y:a},{x:o.x,y:a},o];return l=l.map(r),"M"+l[0]+"C"+l[1]+" "+l[2]+" "+l[3]}var t=Me,e=xe,r=Yu;return n.source=function(e){return arguments.length?(t=En(e),n):t},n.target=function(t){return arguments.length?(e=En(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Yu,e=n.projection;return n.projection=function(n){return arguments.length?e(Zu(t=n)):t},n},ao.svg.symbol=function(){function n(n,r){return(Ul.get(t.call(this,n,r))||$u)(e.call(this,n,r))}var t=Xu,e=Vu;return n.type=function(e){return arguments.length?(t=En(e),n):t},n.size=function(t){return arguments.length?(e=En(t),n):e},n};var Ul=ao.map({circle:$u,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Fl)),e=t*Fl;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ao.svg.symbolTypes=Ul.keys();var jl=Math.sqrt(3),Fl=Math.tan(30*Yo);Co.transition=function(n){for(var t,e,r=Hl||++Zl,i=Ku(n),u=[],o=Ol||{time:Date.now(),ease:Nr,delay:0,duration:250},a=-1,l=this.length;++a<l;){u.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(e=c[f])&&Qu(e,f,i,r,o),t.push(e)}return Wu(u,i,r)},Co.interrupt=function(n){return this.each(null==n?Il:Bu(Ku(n)))};var Hl,Ol,Il=Bu(Ku()),Yl=[],Zl=0;Yl.call=Co.call,Yl.empty=Co.empty,Yl.node=Co.node,Yl.size=Co.size,ao.transition=function(n,t){return n&&n.transition?Hl?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Yl,Yl.select=function(n){var t,e,r,i=this.id,u=this.namespace,o=[];n=A(n);for(var a=-1,l=this.length;++a<l;){o.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(r=c[f])&&(e=n.call(r,r.__data__,f,a))?("__data__"in r&&(e.__data__=r.__data__),Qu(e,f,u,i,r[u][i]),t.push(e)):t.push(null)}return Wu(o,u,i)},Yl.selectAll=function(n){var t,e,r,i,u,o=this.id,a=this.namespace,l=[];n=C(n);for(var c=-1,f=this.length;++c<f;)for(var s=this[c],h=-1,p=s.length;++h<p;)if(r=s[h]){u=r[a][o],e=n.call(r,r.__data__,h,c),l.push(t=[]);for(var g=-1,v=e.length;++g<v;)(i=e[g])&&Qu(i,g,a,o,u),t.push(i)}return Wu(l,a,o)},Yl.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var e=this[u],a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return Wu(i,this.namespace,this.id)},Yl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(i){i[r][e].tween.set(n,t)})},Yl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?$r:Mr,a=ao.ns.qualify(n);return Ju(this,"attr."+n,t,a.local?u:i)},Yl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(i));return r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?r:e)},Yl.style=function(n,e,r){function i(){this.style.removeProperty(n)}function u(e){return null==e?i:(e+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==e&&(i=Mr(u,e),function(t){this.style.setProperty(n,i(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Ju(this,"style."+n,e,u)},Yl.styleTween=function(n,e,r){function i(i,u){var o=e.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,i)},Yl.text=function(n){return Ju(this,"text",n,Gu)},Yl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Yl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),Y(this,function(r){r[e][t].ease=n}))},Yl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,i,u){r[e][t].delay=+n.call(r,r.__data__,i,u)}:(n=+n,function(r){r[e][t].delay=n}))},Yl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,i,u){r[e][t].duration=Math.max(1,n.call(r,r.__data__,i,u))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Yl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var i=Ol,u=Hl;try{Hl=e,Y(this,function(t,i,u){Ol=t[r][e],n.call(t,t.__data__,i,u)})}finally{Ol=i,Hl=u}}else Y(this,function(i){var u=i[r][e];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Yl.transition=function(){for(var n,t,e,r,i=this.id,u=++Zl,o=this.namespace,a=[],l=0,c=this.length;c>l;l++){a.push(n=[]);for(var t=this[l],f=0,s=t.length;s>f;f++)(e=t[f])&&(r=e[o][i],Qu(e,f,o,u,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Wu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,c=ao.select(this),f=this.__chart__||e,s=this.__chart__=e.copy(),h=null==l?s.ticks?s.ticks.apply(s,a):s.domain():l,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,g=c.selectAll(".tick").data(h,s),v=g.enter().insert("g",".domain").attr("class","tick").style("opacity",Uo),d=ao.transition(g.exit()).style("opacity",Uo).remove(),y=ao.transition(g.order()).style("opacity",1),M=Math.max(i,0)+o,x=Zi(s),b=c.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ao.transition(b));v.append("line"),v.append("text");var w,S,k,N,E=v.select("line"),A=y.select("line"),C=g.select("text").text(p),z=v.select("text"),L=y.select("text"),q="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=no,w="x",k="y",S="x2",N="y2",C.attr("dy",0>q?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+q*u+"V0H"+x[1]+"V"+q*u)):(n=to,w="y",k="x",S="y2",N="x2",C.attr("dy",".32em").style("text-anchor",0>q?"end":"start"),_.attr("d","M"+q*u+","+x[0]+"H0V"+x[1]+"H"+q*u)),E.attr(N,q*i),z.attr(k,q*M),A.attr(S,0).attr(N,q*i),L.attr(w,0).attr(k,q*M),s.rangeBand){var T=s,R=T.rangeBand()/2;f=s=function(n){return T(n)+R}}else f.rangeBand?f=s:d.call(n,s,f);v.call(n,f,s),y.call(n,s,s)})}var t,e=ao.scale.linear(),r=Vl,i=6,u=6,o=3,a=[10],l=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Xl?t+"":Vl,n):r},n.ticks=function(){return arguments.length?(a=co(arguments),n):a},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(i=+t,u=+arguments[e-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Vl="bottom",Xl={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return $l[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,s=ao.transition(t),h=ao.transition(o);c&&(l=Zi(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),r(s)),f&&(l=Zi(f),h.attr("y",l[0]).attr("height",l[1]-l[0]),i(s)),e(s)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(C||(M=null,L[0]-=s[1],L[1]-=h[1],C=2),S())}function v(){32==ao.event.keyCode&&2==C&&(L[0]+=s[1],L[1]+=h[1],C=0,S())}function d(){var n=ao.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ao.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),L[0]=s[+(n[0]<M[0])],L[1]=h[+(n[1]<M[1])]):M=null),E&&y(n,c,0)&&(r(k),t=!0),A&&y(n,f,1)&&(i(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function y(n,t,e){var r,i,u=Zi(t),l=u[0],c=u[1],f=L[e],v=e?h:s,d=v[1]-v[0];return C&&(l-=f,c-=d+f),r=(e?g:p)?Math.max(l,Math.min(c,n[e])):n[e],C?i=(r+=f)+d:(M&&(f=Math.max(l,Math.min(c,2*M[e]-r))),r>f?(i=r,r=f):i=f),v[0]!=r||v[1]!=i?(e?a=null:o=null,v[0]=r,v[1]=i,!0):void 0}function m(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ao.select(ao.event.target),w=l.of(b,arguments),k=ao.select(b),N=_.datum(),E=!/^(n|s)$/.test(N)&&c,A=!/^(e|w)$/.test(N)&&f,C=_.classed("extent"),z=W(b),L=ao.mouse(b),q=ao.select(t(b)).on("keydown.brush",u).on("keyup.brush",v);if(ao.event.changedTouches?q.on("touchmove.brush",d).on("touchend.brush",m):q.on("mousemove.brush",d).on("mouseup.brush",m),k.interrupt().selectAll("*").interrupt(),C)L[0]=s[0]-L[0],L[1]=h[0]-L[1];else if(N){var T=+/w$/.test(N),R=+/^n/.test(N);x=[s[1-T]-L[0],h[1-R]-L[1]],L[0]=s[T],L[1]=h[R]}else ao.event.altKey&&(M=L.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,l=N(n,"brushstart","brush","brushend"),c=null,f=null,s=[0,0],h=[0,0],p=!0,g=!0,v=Bl[0];return n.event=function(n){n.each(function(){var n=l.of(this,arguments),t={x:s,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Hl?ao.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,s=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(s,t.x),r=xr(h,t.y);return o=a=null,function(i){s=t.x=e(i),h=t.y=r(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=Bl[!c<<1|!f],n):c},n.y=function(t){return arguments.length?(f=t,v=Bl[!c<<1|!f],n):f},n.clamp=function(t){return arguments.length?(c&&f?(p=!!t[0],g=!!t[1]):c?p=!!t:f&&(g=!!t),n):c&&f?[p,g]:c?p:f?g:null},n.extent=function(t){var e,r,i,u,l;return arguments.length?(c&&(e=t[0],r=t[1],f&&(e=e[0],r=r[0]),o=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(l=e,e=r,r=l),e==s[0]&&r==s[1]||(s=[e,r])),f&&(i=t[0],u=t[1],c&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(l=i,i=u,u=l),i==h[0]&&u==h[1]||(h=[i,u])),n):(c&&(o?(e=o[0],r=o[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(l=e,e=r,r=l))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(l=i,i=u,u=l))),c&&f?[[e,i],[r,u]]:c?[e,r]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,l,"on")};var $l={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Wl=ga.format=xa.timeFormat,Jl=Wl.utc,Gl=Jl("%Y-%m-%dT%H:%M:%S.%LZ");Wl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?eo:Gl,eo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},eo.toString=Gl.toString,ga.second=On(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ga.seconds=ga.second.range,ga.seconds.utc=ga.second.utc.range,ga.minute=On(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ga.minutes=ga.minute.range,ga.minutes.utc=ga.minute.utc.range,ga.hour=On(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ga.hours=ga.hour.range,ga.hours.utc=ga.hour.utc.range,ga.month=On(function(n){return n=ga.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ga.months=ga.month.range,ga.months.utc=ga.month.utc.range;var Kl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Ql=[[ga.second,1],[ga.second,5],[ga.second,15],[ga.second,30],[ga.minute,1],[ga.minute,5],[ga.minute,15],[ga.minute,30],[ga.hour,1],[ga.hour,3],[ga.hour,6],[ga.hour,12],[ga.day,1],[ga.day,2],[ga.week,1],[ga.month,1],[ga.month,3],[ga.year,1]],nc=Wl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",zt]]),tc={range:function(n,t,e){return ao.range(Math.ceil(n/e)*e,+t,e).map(io)},floor:m,ceil:m};Ql.year=ga.year,ga.scale=function(){return ro(ao.scale.linear(),Ql,nc)};var ec=Ql.map(function(n){return[n[0].utc,n[1]]}),rc=Jl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",zt]]);ec.year=ga.year.utc,ga.scale.utc=function(){return ro(ao.scale.linear(),ec,rc)},ao.text=An(function(n){return n.responseText}),ao.json=function(n,t){return Cn(n,"application/json",uo,t)},ao.html=function(n,t){return Cn(n,"text/html",oo,t)},ao.xml=An(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosDiagnostic.js b/xos/core/xoslib/static/js/xosDiagnostic.js
new file mode 100644
index 0000000..893b815
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosDiagnostic.js
@@ -0,0 +1,1877 @@
+//Autogenerated, do not edit!!!
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic', ['ngResource', 'ngCookies', 'ngLodash', 'ngAnimate', 'ui.router', 'xos.helpers']).config(["$stateProvider", function ($stateProvider) {
+    $stateProvider.state('home', {
+      url: '/',
+      template: '<diagnostic-container></diagnostic-container>'
+    });
+  }]).config(["$httpProvider", function ($httpProvider) {
+    $httpProvider.interceptors.push('NoHyperlinks');
+  }]).run(["$log", function ($log) {
+    $log.info('Diagnostic Started');
+  }]);
+})();
+angular.module("xos.diagnostic").run(["$templateCache", function($templateCache) {$templateCache.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>");
+$templateCache.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>");
+$templateCache.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 -->");}]);
+'use strict';
+
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic').directive('subscriberModal', function () {
+    return {
+      scope: {
+        subscribers: '=',
+        open: '='
+      },
+      bindToController: true,
+      restrict: 'E',
+      templateUrl: 'templates/subscriber-modal.tpl.html',
+      controllerAs: 'vm',
+      controller: ["$rootScope", function controller($rootScope) {
+        var _this = this;
+
+        this.close = function () {
+          _this.open = false;
+        };
+
+        this.select = function (subscriber) {
+          $rootScope.$emit('subscriber.selected', subscriber);
+          _this.close();
+        };
+      }]
+    };
+  });
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').service('ServiceTopologyHelper', ["$rootScope", "$window", "$log", "lodash", "ServiceRelation", "serviceTopologyConfig", "d3", function ($rootScope, $window, $log, lodash, ServiceRelation, serviceTopologyConfig, d3) {
+
+    // NOTE not used anymore
+    var drawLegend = function drawLegend(svg) {
+      var legendContainer = svg.append('g').attr({
+        'class': 'legend'
+      });
+
+      legendContainer.append('rect').attr({
+        transform: function transform(d) {
+          return 'translate(10, 80)';
+        },
+        width: 100,
+        height: 100
+      });
+
+      // service
+      var service = legendContainer.append('g').attr({
+        'class': 'node service'
+      });
+
+      service.append('circle').attr({
+        r: serviceTopologyConfig.circle.radius,
+        transform: function transform(d) {
+          return 'translate(30, 100)';
+        }
+      });
+
+      service.append('text').attr({
+        transform: function transform(d) {
+          return 'translate(45, 100)';
+        },
+        dy: '.35em'
+      }).text('Service').style('fill-opacity', 1);
+
+      // slice
+      var slice = legendContainer.append('g').attr({
+        'class': 'node slice'
+      });
+
+      slice.append('rect').attr({
+        width: 20,
+        height: 20,
+        x: -10,
+        y: -10,
+        transform: function transform(d) {
+          return 'translate(30, 130)';
+        }
+      });
+
+      slice.append('text').attr({
+        transform: function transform(d) {
+          return 'translate(45, 130)';
+        },
+        dy: '.35em'
+      }).text('Slices').style('fill-opacity', 1);
+
+      // instance
+      var instance = legendContainer.append('g').attr({
+        'class': 'node instance'
+      });
+
+      instance.append('rect').attr({
+        width: 20,
+        height: 20,
+        x: -10,
+        y: -10,
+        transform: function transform(d) {
+          return 'translate(30, 160)';
+        }
+      });
+
+      instance.append('text').attr({
+        transform: function transform(d) {
+          return 'translate(45, 160)';
+        },
+        dy: '.35em'
+      }).text('Instances').style('fill-opacity', 1);
+    };
+
+    var _svg, _layout, _source;
+
+    var i = 0;
+
+    // given a canvas, a layout and a data source, draw a tree layout
+    var updateTree = function updateTree(svg, layout, source) {
+
+      //cache data
+      _svg = svg;
+      _layout = layout;
+      _source = source;
+
+      var maxDepth = ServiceRelation.depthOf(source);
+
+      var diagonal = d3.svg.diagonal().projection(function (d) {
+        return [d.y, d.x];
+      });
+
+      // Compute the new tree layout.
+      var nodes = layout.nodes(source).reverse(),
+          links = layout.links(nodes);
+
+      // Normalize for fixed-depth.
+      nodes.forEach(function (d) {
+        // position the child node horizontally
+        var step = ($window.innerWidth - serviceTopologyConfig.widthMargin * 2) / maxDepth;
+        d.y = d.depth * step;
+      });
+
+      // 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': function _class(d) {
+          return 'node ' + d.type;
+        },
+        transform: function transform(d) {
+          return d.x && d.y ? 'translate(' + d.y + ', ' + d.x + ')' : 'translate(' + source.y0 + ', ' + source.x0 + ')';
+        }
+      });
+
+      var subscriberNodes = nodeEnter.filter('.subscriber');
+      var internetNodes = nodeEnter.filter('.router');
+      var serviceNodes = nodeEnter.filter('.service');
+
+      subscriberNodes.append('rect').attr(serviceTopologyConfig.square);
+
+      internetNodes.append('rect').attr(serviceTopologyConfig.square);
+
+      serviceNodes.append('circle').attr('r', 1e-6).style('fill', function (d) {
+        return d._children ? 'lightsteelblue' : '#fff';
+      }).on('click', serviceClick);
+
+      nodeEnter.append('text').attr({
+        x: function x(d) {
+          return d.children ? -serviceTopologyConfig.circle.selectedRadius - 3 : serviceTopologyConfig.circle.selectedRadius + 3;
+        },
+        dy: '.35em',
+        transform: function transform(d) {
+          if (d.children && d.parent) {
+            if (d.parent.x < d.x) {
+              return 'rotate(-30)';
+            }
+            return 'rotate(30)';
+          }
+        },
+        'text-anchor': function textAnchor(d) {
+          return 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(serviceTopologyConfig.duration).attr({
+        'transform': function transform(d) {
+          return 'translate(' + d.y + ',' + d.x + ')';
+        }
+      });
+
+      nodeUpdate.select('circle').attr('r', function (d) {
+        return d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius;
+      }).style('fill', function (d) {
+        return d.selected ? 'lightsteelblue' : '#fff';
+      });
+
+      nodeUpdate.select('text').style('fill-opacity', 1);
+
+      // Transition exiting nodes to the parent's new position.
+      var nodeExit = node.exit().transition().duration(serviceTopologyConfig.duration).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', function (d) {
+        return 'link ' + d.target.type + ' ' + (d.target.active ? '' : 'active');
+      }).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(serviceTopologyConfig.duration).attr('d', diagonal);
+
+      // Transition exiting nodes to the parent's new position.
+      link.exit().transition().duration(serviceTopologyConfig.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;
+      });
+    };
+
+    var serviceClick = function serviceClick(d) {
+
+      // if was selected
+      if (d.selected) {
+        d.selected = !d.selected;
+        $rootScope.$emit('instance.detail.hide', {});
+        return updateTree(_svg, _layout, _source);
+      }
+
+      $rootScope.$emit('instance.detail', { name: d.name, service: d.service, tenant: d.tenant });
+
+      // unselect all
+      _svg.selectAll('circle').each(function (d) {
+        return d.selected = false;
+      });
+
+      // toggling selected status
+      d.selected = !d.selected;
+
+      updateTree(_svg, _layout, _source);
+    };
+
+    this.updateTree = updateTree;
+    this.drawLegend = drawLegend;
+  }]);
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').directive('serviceTopology', function () {
+    return {
+      restrict: 'E',
+      scope: {
+        serviceChain: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      template: '',
+      controller: ["$element", "$window", "$scope", "d3", "serviceTopologyConfig", "ServiceRelation", "Slice", "Instances", "Subscribers", "ServiceTopologyHelper", function controller($element, $window, $scope, d3, serviceTopologyConfig, ServiceRelation, Slice, Instances, Subscribers, ServiceTopologyHelper) {
+        var _this = this;
+
+        var el = $element[0];
+
+        d3.select(window).on('resize', function () {
+          draw(_this.serviceChain);
+        });
+
+        var root, svg;
+
+        var draw = function draw(tree) {
+
+          if (!tree) {
+            console.error('Tree is missing');
+            return;
+          }
+
+          // TODO update instead clear and redraw
+
+          // clean
+          d3.select($element[0]).select('svg').remove();
+
+          var width = el.clientWidth - serviceTopologyConfig.widthMargin * 2;
+          var height = el.clientHeight - serviceTopologyConfig.heightMargin * 2;
+
+          var treeLayout = d3.layout.tree().size([height, width]);
+
+          svg = d3.select($element[0]).append('svg').style('width', el.clientWidth + 'px').style('height', el.clientHeight + 'px');
+
+          var treeContainer = svg.append('g').attr('transform', 'translate(' + serviceTopologyConfig.widthMargin * 4 + ',' + serviceTopologyConfig.heightMargin + ')');
+
+          root = tree;
+          root.x0 = height / 2;
+          root.y0 = width / 2;
+
+          // ServiceTopologyHelper.drawLegend(svg);
+          ServiceTopologyHelper.updateTree(treeContainer, treeLayout, root);
+        };
+
+        this.getInstances = function (slice) {
+          Instances.query({ slice: slice.id }).$promise.then(function (instances) {
+            _this.selectedSlice = slice;
+            _this.instances = instances;
+          })['catch'](function (e) {
+            _this.errors = e;
+            throw new Error(e);
+          });
+        };
+
+        $scope.$watch(function () {
+          return _this.serviceChain;
+        }, function (chain) {
+          console.log(chain);
+          if (angular.isDefined(chain)) {
+            draw(chain);
+          }
+        });
+      }]
+    };
+  });
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').service('Services', ["$resource", function ($resource) {
+    return $resource('/xos/services/:id', { id: '@id' });
+  }]).service('Tenant', ["$resource", function ($resource) {
+    return $resource('/xos/tenants', { id: '@id' }, {
+      queryVsgInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function response(res) {
+
+            // NOTE
+            // Note that VCPETenant is now VSGTenant.
+
+            var instances = [];
+
+            angular.forEach(res.data, function (tenant) {
+              var info = JSON.parse(tenant.service_specific_attribute);
+              if (info && info.instance_id) {
+                instances.push(info.instance_id);
+              }
+            });
+
+            return instances;
+          }
+        }
+      },
+      getSubscriberTag: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function response(res) {
+            // NOTE we should receive only one vOLT tenant here
+            return JSON.parse(res.data[0].service_specific_attribute);
+          }
+        }
+      }
+    });
+  }]).service('Ceilometer', ["$http", "$q", "Instances", function ($http, $q, Instances) {
+    var _this = this;
+
+    /**
+    * Get stats for a single instance
+    */
+    this.getInstanceStats = function (instanceUuid) {
+      var deferred = $q.defer();
+
+      $http.get('/xoslib/xos-instance-statistics', { params: { 'instance-uuid': instanceUuid } }).then(function (res) {
+        deferred.resolve(res.data);
+      })['catch'](function (e) {
+        deferred.reject(e);
+      });
+
+      return deferred.promise;
+    };
+
+    /**
+    * Collect stats for an array of instances
+    */
+    this.getInstancesStats = function (instances) {
+      var deferred = $q.defer();
+      var instancePromises = [];
+      var instanceList = [];
+
+      // retrieve instance details
+      instances.forEach(function (instanceId) {
+        instancePromises.push(Instances.get({ id: instanceId }).$promise);
+      });
+
+      // get all instance data
+      $q.all(instancePromises).then(function (_instanceList) {
+        instanceList = _instanceList;
+        var promises = [];
+        // foreach instance query stats
+        instanceList.forEach(function (instance) {
+          promises.push(_this.getInstanceStats(instance.instance_uuid));
+        });
+        return $q.all(promises);
+      }).then(function (stats) {
+        // augment instance with stats information
+        instanceList.map(function (instance, i) {
+          instance.stats = stats[i];
+        });
+        deferred.resolve(instanceList);
+      })['catch'](deferred.reject);
+
+      return deferred.promise;
+    };
+
+    this.getContainerStats = function (containerName) {
+      var deferred = $q.defer();
+
+      var res = {};
+
+      $http.get('/xoslib/meterstatistics', { params: { 'resource': containerName } }).then(function (containerStats) {
+        res.stats = containerStats.data;
+        return $http.get('/xoslib/meterstatistics', { params: { 'resource': containerName + '-eth0' } });
+      }).then(function (portStats) {
+        res.port = {
+          eth0: portStats.data
+        };
+        return $http.get('/xoslib/meterstatistics', { params: { 'resource': containerName + '-eth1' } });
+      }).then(function (portStats) {
+        res.port.eth1 = portStats.data;
+        deferred.resolve(res);
+      })['catch'](function (e) {
+        deferred.reject(e);
+      });
+
+      return deferred.promise;
+    };
+  }]).service('Slice', ["$resource", function ($resource) {
+    return $resource('/xos/slices', { id: '@id' });
+  }]).service('Instances', ["$resource", function ($resource) {
+    return $resource('/xos/instances/:id', { id: '@id' });
+  }]).service('Node', ["$resource", "$q", "Instances", function ($resource, $q, Instances) {
+    return $resource('/xos/nodes', { id: '@id' }, {
+      queryWithInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function response(res) {
+
+            // TODO update the API to include instances in nodes
+            // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
+
+            var deferred = $q.defer();
+
+            var requests = [];
+
+            angular.forEach(res.data, function (node) {
+              requests.push(Instances.query({ node: node.id }).$promise);
+            });
+
+            $q.all(requests).then(function (list) {
+              res.data.map(function (node, i) {
+                node.instances = list[i];
+                return node;
+              });
+              deferred.resolve(res.data);
+            });
+
+            return deferred.promise;
+          }
+        }
+      }
+    });
+  }]).service('Subscribers', ["$resource", "$q", "SubscriberDevice", function ($resource, $q, SubscriberDevice) {
+    return $resource('/xos/subscribers/:id', { id: '@id' }, {
+      queryWithDevices: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function response(res) {
+
+            /**
+            * For each subscriber retrieve devices and append them
+            */
+
+            var deferred = $q.defer();
+
+            var requests = [];
+
+            angular.forEach(res.data, function (subscriber) {
+              requests.push(SubscriberDevice.query({ id: subscriber.id }).$promise);
+            });
+
+            $q.all(requests).then(function (list) {
+
+              // adding devices
+
+              res.data.map(function (subscriber, i) {
+                subscriber.devices = list[i];
+                subscriber.type = 'subscriber';
+
+                subscriber.devices.map(function (d) {
+                  return d.type = 'device';
+                });
+
+                return subscriber;
+              });
+
+              // faking to have 2 subscriber
+              // res.data.push(angular.copy(res.data[0]));
+
+              deferred.resolve(res.data);
+            });
+
+            return deferred.promise;
+          }
+        }
+      },
+      getWithDevices: {
+        method: 'GET',
+        isArray: false,
+        interceptor: {
+          response: function response(res) {
+            var d = $q.defer();
+
+            SubscriberDevice.query({ id: res.data.id }).$promise.then(function (devices) {
+              devices.map(function (d) {
+                return d.type = 'device';
+              });
+              res.data.devices = devices;
+              res.data.type = 'subscriber';
+              d.resolve(res.data);
+            })['catch'](function (err) {
+              d.reject(err);
+            });
+
+            return d.promise;
+          }
+        }
+      }
+    });
+  }]).service('SubscriberDevice', ["$resource", function ($resource) {
+    return $resource('/xoslib/rs/subscriber/:id/users/', { id: '@id' });
+  }]).service('ServiceRelation', ["$q", "lodash", "Services", "Tenant", "Slice", "Instances", function ($q, lodash, Services, Tenant, Slice, Instances) {
+
+    // count the mas depth of an object
+    var depthOf = function 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;
+    };
+
+    // find all the relation defined for a given root
+    var findLevelRelation = function findLevelRelation(tenants, rootId) {
+      return lodash.filter(tenants, function (service) {
+        return service.subscriber_service === rootId;
+      });
+    };
+
+    var findSpecificInformation = function findSpecificInformation(tenants, rootId) {
+      var tenants = lodash.filter(tenants, function (service) {
+        return service.provider_service === rootId && service.subscriber_tenant;
+      });
+
+      var info;
+
+      tenants.forEach(function (tenant) {
+        if (tenant.service_specific_attribute) {
+          info = JSON.parse(tenant.service_specific_attribute);
+        }
+      });
+
+      return info;
+    };
+
+    // find all the service defined by a given array of relations
+    var findLevelServices = function findLevelServices(relations, services) {
+      var levelServices = [];
+      lodash.forEach(relations, function (tenant) {
+        var service = lodash.find(services, { id: tenant.provider_service });
+        levelServices.push(service);
+      });
+      return levelServices;
+    };
+
+    var buildLevel = function buildLevel(tenants, services, rootService, rootTenant) {
+      var parentName = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
+
+      // build an array of unlinked services
+      // these are the services that should still placed in the tree
+      var unlinkedServices = lodash.difference(services, [rootService]);
+
+      // find all relations relative to this rootElement
+      var levelRelation = findLevelRelation(tenants, rootService.id);
+      // find all items related to rootElement
+      var levelServices = findLevelServices(levelRelation, services);
+
+      // remove this item from the list (performance
+      unlinkedServices = lodash.difference(unlinkedServices, levelServices);
+
+      rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
+
+      var tree = {
+        name: rootService.humanReadableName,
+        parent: parentName,
+        type: 'service',
+        service: rootService,
+        tenant: rootTenant,
+        children: []
+      };
+
+      lodash.forEach(levelServices, function (service) {
+        var tenant = lodash.find(tenants, { subscriber_tenant: rootTenant.id, provider_service: service.id });
+        tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
+      });
+
+      // if it is the last element append internet
+      if (tree.children.length === 0) {
+        tree.children.push({
+          name: 'Router',
+          type: 'router',
+          children: []
+        });
+      }
+
+      return tree;
+    };
+
+    var buildSubscriberServiceTree = function buildSubscriberServiceTree(services, tenants) {
+      var subscriber = arguments.length <= 2 || arguments[2] === undefined ? { id: 1, name: 'fakeSubs' } : arguments[2];
+
+      // find the root service
+      // it is the one attached to subsriber_root
+      // as now we have only one root so this can work
+      var rootTenant = lodash.find(tenants, { subscriber_root: subscriber.id });
+      var rootService = lodash.find(services, { id: rootTenant.provider_service });
+
+      var serviceTree = buildLevel(tenants, services, rootService, rootTenant);
+
+      return {
+        name: subscriber.name,
+        parent: null,
+        type: 'subscriber',
+        children: [serviceTree]
+      };
+    };
+
+    // applying domain knowledge to build the global service tree
+    var buildServiceTree = function buildServiceTree(services, tenants) {
+
+      // TODO refactor
+      var buildChild = function buildChild(services, tenants, currentService) {
+
+        var response = {
+          type: 'service',
+          name: currentService.humanReadableName,
+          service: currentService
+        };
+
+        var tenant = lodash.find(tenants, { subscriber_service: currentService.id });
+        if (tenant) {
+          var next = lodash.find(services, { id: tenant.provider_service });
+          response.children = [buildChild(services, tenants, next)];
+        } else {
+          response.children = [{
+            name: 'Router',
+            type: 'router',
+            children: []
+          }];
+        }
+        delete currentService.id; // conflict with d3
+        return response;
+      };
+
+      var baseService = lodash.find(services, { id: 3 });
+
+      if (!angular.isDefined(baseService)) {
+        console.error('Missing Base service!');
+        return;
+      }
+
+      var baseData = {
+        name: 'Subscriber',
+        type: 'subscriber',
+        parent: null,
+        children: [buildChild(services, tenants, baseService)]
+      };
+      return baseData;
+    };
+
+    var getBySubscriber = function getBySubscriber(subscriber) {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise.then(function (res) {
+        services = res;
+        return Tenant.query().$promise;
+      }).then(function (res) {
+        tenants = res;
+        deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
+      })['catch'](function (e) {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    };
+
+    var get = function get() {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise.then(function (res) {
+        services = res;
+        return Tenant.query({ kind: 'coarse' }).$promise;
+      }).then(function (res) {
+        tenants = res;
+        deferred.resolve(buildServiceTree(services, tenants));
+      })['catch'](function (e) {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    };
+
+    // export APIs
+    return {
+      get: get,
+      buildServiceTree: buildServiceTree,
+      getBySubscriber: getBySubscriber,
+      buildLevel: buildLevel,
+      buildSubscriberServiceTree: buildSubscriberServiceTree,
+      findLevelRelation: findLevelRelation,
+      findLevelServices: findLevelServices,
+      depthOf: depthOf,
+      findSpecificInformation: findSpecificInformation
+    };
+  }]);
+})();
+'use strict';
+
+var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
+
+(function () {
+  angular.module('xos.diagnostic').service('RackHelper', ["serviceTopologyConfig", "lodash", function (serviceTopologyConfig, lodash) {
+    var _this = this;
+
+    this.getComputeNodeLabelSize = function () {
+      return serviceTopologyConfig.computeNode.labelHeight + serviceTopologyConfig.instance.margin * 2;
+    };
+
+    /**
+    * Given a list of instance should get the Compute Node size.
+    * They are placed in rows of 2 with 5px margin on each side.
+    */
+
+    this.getComputeNodeSize = lodash.memoize(function (instances) {
+      var width = serviceTopologyConfig.instance.margin * 3 + serviceTopologyConfig.instance.width * 2;
+
+      var rows = Math.round(instances.length / 2);
+
+      var labelSpace = _this.getComputeNodeLabelSize();
+
+      var height = serviceTopologyConfig.instance.height * rows + serviceTopologyConfig.instance.margin * (rows + 1) + labelSpace;
+
+      return [width, height];
+    });
+
+    /**
+    * Give a list on Compute Node should calculate the Rack Size.
+    * Compute nodes are placed in a single column with 5px margin on each side.
+    */
+    this.getRackSize = function (nodes) {
+
+      var width = 0;
+      var height = serviceTopologyConfig.computeNode.margin;
+
+      lodash.forEach(nodes, function (node) {
+        var _getComputeNodeSize = _this.getComputeNodeSize(node.instances);
+
+        var _getComputeNodeSize2 = _slicedToArray(_getComputeNodeSize, 2);
+
+        var nodeWidth = _getComputeNodeSize2[0];
+        var nodeHeight = _getComputeNodeSize2[1];
+
+        width = nodeWidth + serviceTopologyConfig.computeNode.margin * 2;
+        height += nodeHeight + serviceTopologyConfig.computeNode.margin;
+      });
+
+      return [width, height];
+    };
+
+    /**
+    * Given an instance index, return the coordinates
+    */
+
+    this.getInstancePosition = function (position) {
+      var row = Math.floor(position / 2);
+      var column = position % 2 ? 1 : 0;
+
+      // add ComputeNode label size
+      var labelSpace = _this.getComputeNodeLabelSize();
+
+      // x = margin + (width * column) + ( maring * column)
+      var x = serviceTopologyConfig.instance.margin + serviceTopologyConfig.instance.width * column + serviceTopologyConfig.instance.margin * column;
+
+      // y = label + margin + (height * row) + ( maring * row)
+      var y = labelSpace + serviceTopologyConfig.instance.margin + serviceTopologyConfig.instance.height * row + serviceTopologyConfig.instance.margin * row;
+      return [x, y];
+    };
+
+    /**
+    * Given an Compute Node index, return the coordinates
+    */
+
+    this.getComputeNodePosition = function (nodes, position) {
+
+      var x = serviceTopologyConfig.computeNode.margin;
+
+      var previousElEight = lodash.reduce(nodes.slice(0, position), function (val, node) {
+        return val + _this.getComputeNodeSize(node.instances)[1];
+      }, 0);
+
+      var y = serviceTopologyConfig.computeNode.margin + serviceTopologyConfig.computeNode.margin * position + previousElEight;
+
+      return [x, y];
+    };
+  }]);
+})();
+'use strict';
+
+var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
+
+(function () {
+  'use strict';
+
+  var shapes = {
+    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'
+  };
+
+  var computeNodeId = 0;
+  var instanceId = 0;
+
+  angular.module('xos.diagnostic').service('NodeDrawer', ["d3", "serviceTopologyConfig", "RackHelper", "lodash", function (d3, serviceTopologyConfig, RackHelper, lodash) {
+    var _this2 = this;
+
+    var _this = this;
+
+    this.addNetworks = function (nodes) {
+      nodes.append('path').attr({
+        d: shapes.cloud,
+        transform: 'translate(-63, -52), scale(0.5)',
+        'class': 'cloud'
+      });
+
+      nodes.append('text').attr({
+        'text-anchor': 'middle'
+      }).text(function (d) {
+        return d.name;
+      });
+
+      nodes.each(function (n) {
+        var currentNode = d3.select(this);
+        // cicle trouch node to add Tags and Public IP
+        if (n.name === 'LAN' && angular.isDefined(n.subscriberTag)) {
+          currentNode.append('text').attr({
+            'text-anchor': 'middle',
+            y: 40
+          }).text(function () {
+            return 'C-Tag: ' + n.subscriberTag.cTag;
+          });
+
+          currentNode.append('text').attr({
+            'text-anchor': 'middle',
+            y: 60
+          }).text(function () {
+            return 'S-Tag: ' + n.subscriberTag.sTag;
+          });
+        }
+
+        if (n.name === 'WAN' && angular.isDefined(n.subscriberIP)) {
+          currentNode.append('text').attr({
+            'text-anchor': 'middle',
+            y: 40
+          }).text(function () {
+            return 'Public IP: ' + n.subscriberIP;
+          });
+        }
+      });
+    };
+
+    this.addRack = function (nodes) {
+
+      // loop because of D3
+      // rack will be only one
+      nodes.each(function (d) {
+        var _RackHelper$getRackSize = RackHelper.getRackSize(d.computeNodes);
+
+        var _RackHelper$getRackSize2 = _slicedToArray(_RackHelper$getRackSize, 2);
+
+        var w = _RackHelper$getRackSize2[0];
+        var h = _RackHelper$getRackSize2[1];
+
+        // TODO update instead of delete and redraw
+        nodes.select('g').remove();
+
+        var rack = nodes.append('g');
+
+        rack.attr({
+          transform: 'translate(0,0)'
+        }).transition().duration(serviceTopologyConfig.duration).attr({
+          transform: function transform() {
+            return 'translate(' + -(w / 2) + ', ' + -(h / 2) + ')';
+          }
+        });
+
+        rack.append('rect').attr({
+          width: 0,
+          height: 0
+        }).transition().duration(serviceTopologyConfig.duration).attr({
+          width: w,
+          height: h
+        });
+
+        rack.append('text').attr({
+          'text-anchor': 'middle',
+          y: -10,
+          x: w / 2,
+          opacity: 0
+        }).text(function (d) {
+          return d.name;
+        }).transition().duration(serviceTopologyConfig.duration).attr({
+          opacity: 1
+        });
+
+        _this2.drawComputeNodes(rack, d.computeNodes);
+      });
+    };
+
+    this.drawComputeNodes = function (container, nodes) {
+
+      var elements = container.selectAll('.compute-nodes').data(nodes, function (d) {
+        if (!angular.isString(d.d3Id)) {
+          d.d3Id = 'compute-node-' + ++computeNodeId;
+        }
+        return d.d3Id;
+      });
+
+      var _container$node$getBoundingClientRect = container.node().getBoundingClientRect();
+
+      var width = _container$node$getBoundingClientRect.width;
+      var height = _container$node$getBoundingClientRect.height;
+
+      var nodeContainer = elements.enter().append('g');
+
+      nodeContainer.attr({
+        transform: 'translate(' + width / 2 + ', ' + height / 2 + ')',
+        'class': 'compute-node'
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        transform: function transform(d) {
+          return 'translate(' + RackHelper.getComputeNodePosition(nodes, d.d3Id.replace('compute-node-', '') - 1) + ')';
+        }
+      });
+
+      nodeContainer.append('rect').attr({
+        width: 0,
+        height: 0
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        width: function width(d) {
+          return RackHelper.getComputeNodeSize(d.instances)[0];
+        },
+        height: function height(d) {
+          return RackHelper.getComputeNodeSize(d.instances)[1];
+        }
+      });
+
+      nodeContainer.append('text').attr({
+        'text-anchor': 'start',
+        y: 15, //FIXME
+        x: 10, //FIXME
+        opacity: 0
+      }).text(function (d) {
+        return d.humanReadableName.split('.')[0];
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      // if there are Compute Nodes
+      if (nodeContainer.length > 0) {
+        // draw instances for each compute node
+        nodeContainer.each(function (a) {
+          _this.drawInstances(d3.select(this), a.instances);
+        });
+      }
+    };
+
+    // NOTE Stripping unuseful names to shorten labels.
+    // This is not elegant
+    var formatInstanceName = function formatInstanceName(name) {
+      return name.replace('app_', '').replace('service_', '')
+      // .replace('ovs_', '')
+      .replace('mysite_', '').replace('_instance', '');
+    };
+
+    var getInstanceStatusColor = function getInstanceStatusColor(instance) {
+      function startWith(val, string) {
+        return string.substring(0, val.length) === val;
+      }
+
+      if (startWith('0 - ', instance.backend_status)) {
+        return 'provisioning';
+      }
+      if (startWith('1 - ', instance.backend_status)) {
+        return 'good';
+      }
+      if (startWith('2 - ', instance.backend_status)) {
+        return 'bad';
+      } else {
+        return '';
+      }
+    };
+
+    var drawContainer = function drawContainer(container, docker) {
+
+      var containerBox = container.append('g').attr({
+        'class': 'container',
+        transform: 'translate(' + serviceTopologyConfig.instance.margin + ', 115)'
+      });
+
+      containerBox.append('rect').attr({
+        width: 250 - serviceTopologyConfig.container.margin * 2,
+        height: serviceTopologyConfig.container.height
+      });
+
+      containerBox.append('text').attr({
+        y: 20,
+        x: serviceTopologyConfig.instance.margin,
+        'class': 'name'
+      }).text(docker.name);
+
+      // add stats
+      var interestingMeters = ['memory', 'memory.usage', 'cpu_util'];
+
+      interestingMeters.forEach(function (m, i) {
+        var meter = lodash.find(docker.stats, { meter: m });
+        // if there is no meter stats skip rendering
+        if (!angular.isDefined(meter)) {
+          return;
+        }
+        containerBox.append('text').attr({
+          y: 40 + i * 15,
+          x: serviceTopologyConfig.instance.margin,
+          opacity: 0
+        }).text(meter.description + ': ' + Math.round(meter.value) + ' ' + meter.unit).transition().duration(serviceTopologyConfig.duration).attr({
+          opacity: 1
+        });
+      });
+
+      // add port stats
+      var ports = ['eth0', 'eth1'];
+      var interestingPortMeters = [{
+        meter: 'network.incoming.bytes.rate',
+        label: 'Incoming'
+      }, {
+        meter: 'network.outgoing.bytes.rate',
+        label: 'Outgoing'
+      }];
+
+      ports.forEach(function (p, j) {
+
+        // if there are no port stats skip rendering
+        if (docker.port[p].length === 0) {
+          return;
+        }
+
+        containerBox.append('text').attr({
+          y: 90,
+          x: serviceTopologyConfig.instance.margin + 120 * j,
+          'class': 'name'
+        }).text(docker.name + '-' + p);
+
+        interestingPortMeters.forEach(function (m, i) {
+
+          var meter = lodash.find(docker.port[p], { meter: m.meter });
+          // if there is no meter stats skip rendering
+          if (!angular.isDefined(meter)) {
+            return;
+          }
+          containerBox.append('text').attr({
+            y: 105 + i * 15,
+            x: serviceTopologyConfig.instance.margin + 120 * j,
+            opacity: 0
+          }).text(m.label + ': ' + Math.round(meter.value) + ' ' + meter.unit).transition().duration(serviceTopologyConfig.duration).attr({
+            opacity: 1
+          });
+        });
+      });
+    };
+
+    var showInstanceStats = function showInstanceStats(container, instance) {
+
+      // NOTE this should be dinamically positioned
+      // base on the number of element present
+      var statsContainer = container.append('g').attr({
+        transform: 'translate(200, -120)',
+        'class': 'stats-container'
+      });
+
+      statsContainer.append('line').attr({
+        x1: -160,
+        y1: 120,
+        x2: 0,
+        y2: 50,
+        stroke: 'black',
+        opacity: 0
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      // NOTE rect should be dinamically sized base on the presence of a container
+      var statsHeight = 110;
+      var statsWidth = 250;
+
+      if (instance.container) {
+        statsHeight += serviceTopologyConfig.container.height + serviceTopologyConfig.container.margin * 2;
+      }
+
+      statsContainer.append('rect').attr({
+        width: statsWidth,
+        height: statsHeight,
+        opacity: 0
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      // add instance info
+      statsContainer.append('text').attr({
+        y: 15,
+        x: serviceTopologyConfig.instance.margin,
+        'class': 'name',
+        opacity: 0
+      }).text(instance.humanReadableName).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      statsContainer.append('text').attr({
+        y: 30,
+        x: serviceTopologyConfig.instance.margin,
+        'class': 'ip',
+        opacity: 0
+      }).text(instance.ip).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      // add stats
+      var interestingMeters = ['memory', 'memory.usage', 'cpu', 'vcpus'];
+
+      interestingMeters.forEach(function (m, i) {
+        var meter = lodash.find(instance.stats, { meter: m });
+        statsContainer.append('text').attr({
+          y: 55 + i * 15,
+          x: serviceTopologyConfig.instance.margin,
+          opacity: 0
+        }).text(meter.description + ': ' + Math.round(meter.value) + ' ' + meter.unit).transition().duration(serviceTopologyConfig.duration).attr({
+          opacity: 1
+        });
+      });
+
+      if (instance.container) {
+        // draw container
+        drawContainer(statsContainer, instance.container);
+      }
+    };
+
+    this.drawInstances = function (container, instances) {
+
+      // TODO check for stats field in instance and draw popup
+
+      var _container$node$getBoundingClientRect2 = container.node().getBoundingClientRect();
+
+      var width = _container$node$getBoundingClientRect2.width;
+      var height = _container$node$getBoundingClientRect2.height;
+
+      var elements = container.selectAll('.instances').data(instances, function (d) {
+        return angular.isString(d.d3Id) ? d.d3Id : d.d3Id = 'instance-' + ++instanceId;
+      });
+
+      var instanceContainer = elements.enter().append('g');
+
+      instanceContainer.attr({
+        transform: 'translate(' + width / 2 + ', ' + height / 2 + ')',
+        'class': function _class(d) {
+          return 'instance ' + (d.selected ? 'active' : '') + ' ' + getInstanceStatusColor(d);
+        }
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        transform: function transform(d, i) {
+          return 'translate(' + RackHelper.getInstancePosition(i) + ')';
+        }
+      });
+
+      instanceContainer.append('rect').attr({
+        width: 0,
+        height: 0
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        width: serviceTopologyConfig.instance.width,
+        height: serviceTopologyConfig.instance.height
+      });
+
+      instanceContainer.append('text').attr({
+        'text-anchor': 'middle',
+        y: 23, //FIXME
+        x: 40, //FIXME
+        opacity: 0
+      }).text(function (d) {
+        return formatInstanceName(d.humanReadableName);
+      }).transition().duration(serviceTopologyConfig.duration).attr({
+        opacity: 1
+      });
+
+      // if stats are attached and instance is active,
+      // draw stats
+      instanceContainer.each(function (instance, i) {
+
+        var container = d3.select(this);
+
+        if (angular.isDefined(instance.stats) && instance.selected) {
+          showInstanceStats(container, instance, i);
+        }
+      });
+
+      instanceContainer.on('click', function (d) {
+        console.log('Draw vignette with stats for instance: ' + d.name);
+      });
+    };
+
+    this.addPhisical = function (nodes) {
+      nodes.append('rect').attr(serviceTopologyConfig.square);
+
+      nodes.append('text').attr({
+        'text-anchor': 'middle',
+        y: serviceTopologyConfig.square.y - 10
+      }).text(function (d) {
+        return d.name;
+      });
+    };
+
+    this.addDevice = function (nodes) {
+      nodes.append('circle').attr(serviceTopologyConfig.circle);
+
+      nodes.append('text').attr({
+        'text-anchor': 'end',
+        x: -serviceTopologyConfig.circle.r - 10,
+        y: serviceTopologyConfig.circle.r / 2
+      }).text(function (d) {
+        return d.name || d.mac;
+      });
+    };
+  }]);
+})();
+'use strict';
+
+var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { 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 ($window, $log, $rootScope, lodash, serviceTopologyConfig, NodeDrawer, ChartData) {
+    var _this = this;
+
+    var diagonal,
+        nodes,
+        links,
+        i = 0,
+        svgWidth,
+        svgHeight,
+        layout;
+
+    var baseData = ChartData.logicTopologyData;
+
+    /**
+     * Calculate the horizontal position for each element.
+     * subsrcribers, devices and routers have the same fixed width 20
+     * network have a fixed width 104
+     * rack have a fixed width 105
+     * build and array of 6 elements representing the position of each element in the svg
+     * to equally space them
+     */
+
+    this.computeElementPosition = function (svgWidth) {
+
+      var xPos = [];
+
+      var totalElWidth = lodash.reduce(serviceTopologyConfig.elWidths, function (el, val) {
+        return val + el;
+      }, 0);
+
+      var remainingSpace = svgWidth - totalElWidth - serviceTopologyConfig.widthMargin * 2;
+
+      var step = remainingSpace / (serviceTopologyConfig.elWidths.length - 1);
+
+      lodash.forEach(serviceTopologyConfig.elWidths, function (el, i) {
+
+        // get half of the previous elements width
+        var previousElWidth = 0;
+        if (i !== 0) {
+          previousElWidth = lodash.reduce(serviceTopologyConfig.elWidths.slice(0, i), function (el, val) {
+            return val + el;
+          }, 0);
+        }
+
+        var elPos = serviceTopologyConfig.widthMargin // right margin
+         + step * i // space between elements
+         + el / 2 // this el width
+         + previousElWidth; // previous elements width
+
+        xPos.push(svgWidth - elPos);
+      });
+
+      return xPos;
+    };
+
+    /**
+    * from a nested data structure,
+    * create nodes and links for a D3 Tree Layout
+    */
+    var computeLayout = function computeLayout(data) {
+      var nodes = layout.nodes(data);
+
+      // Normalize for fixed-depth.
+      nodes.forEach(function (d) {
+        // position the child node horizontally
+        d.y = _this.computeElementPosition(svgWidth)[d.depth];
+      });
+
+      var links = layout.links(nodes);
+
+      return [nodes, links];
+    };
+
+    /**
+    * Draw the containing group for any node or update the existing one
+    */
+    var drawNodes = function drawNodes(svg, nodes) {
+      // Update the nodes…
+      var node = svg.selectAll('g.node').data(nodes, function (d) {
+        if (!angular.isString(d.d3Id)) {
+          d.d3Id = 'tree-' + ++i;
+        }
+        return d.d3Id;
+      });
+
+      // Enter any new nodes
+      var nodeEnter = node.enter().append('g').attr({
+        'class': function _class(d) {
+          return 'node ' + d.type;
+        },
+        transform: 'translate(' + svgWidth / 2 + ', ' + svgHeight / 2 + ')'
+      });
+
+      // create Nodes
+      NodeDrawer.addNetworks(node.filter('.network'));
+      NodeDrawer.addRack(node.filter('.rack'));
+      NodeDrawer.addPhisical(node.filter('.router'));
+      NodeDrawer.addPhisical(node.filter('.subscriber'));
+      NodeDrawer.addDevice(node.filter('.device'));
+
+      // add event listener to subscriber
+      node.filter('.subscriber').on('click', function () {
+        $rootScope.$emit('subscriber.modal.open');
+      });
+
+      //update nodes
+      // TODO if data change, only update them
+      // NodeDrawer.updateRack(node.filter('.rack'));
+
+      // Transition nodes to their new position.
+      var nodeUpdate = node.transition().duration(serviceTopologyConfig.duration).attr({
+        'transform': function transform(d) {
+          return 'translate(' + d.y + ',' + d.x + ')';
+        }
+      });
+
+      // TODO handle node remove
+      var nodeExit = node.exit().remove();
+    };
+
+    /**
+    * Handle links in the tree layout
+    */
+    var drawLinks = function drawLinks(svg, links) {
+
+      diagonal = d3.svg.diagonal().projection(function (d) {
+        return [d.y, d.x];
+      });
+
+      // Update the links…
+      var link = svg.selectAll('path.link').data(links, function (d) {
+        return d.target.d3Id;
+      });
+
+      // Enter any new links at the parent's previous position.
+      link.enter().insert('path', 'g').attr('class', function (d) {
+        return 'link ' + d.target.type;
+      }).attr('d', function (d) {
+        var o = { x: svgHeight / 2, y: svgWidth / 2 };
+        return diagonal({ source: o, target: o });
+      });
+
+      // Transition links to their new position.
+      link.transition().duration(serviceTopologyConfig.duration).attr('d', diagonal);
+
+      link.exit().remove();
+    };
+
+    /**
+    * Calculate the svg size and setup tree layout
+    */
+    this.setupTree = function (svg) {
+
+      svgWidth = svg.node().getBoundingClientRect().width;
+      svgHeight = svg.node().getBoundingClientRect().height;
+
+      var width = svgWidth - serviceTopologyConfig.widthMargin * 2;
+      var height = svgHeight - serviceTopologyConfig.heightMargin * 2;
+
+      layout = d3.layout.tree().size([height, width]);
+    };
+
+    /**
+    * Update the tree layout
+    */
+
+    this.updateTree = function (svg) {
+
+      // console.log(baseData);
+
+      var _computeLayout = computeLayout(baseData);
+
+      // Compute the new tree layout.
+
+      var _computeLayout2 = _slicedToArray(_computeLayout, 2);
+
+      nodes = _computeLayout2[0];
+      links = _computeLayout2[1];
+      drawNodes(svg, nodes);
+      drawLinks(svg, links);
+    };
+  }]);
+})();
+'use strict';
+
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic').directive('logicTopology', function () {
+    return {
+      restrict: 'E',
+      scope: {
+        subscribers: '=',
+        selected: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/logicTopology.tpl.html',
+      controller: ["$element", "$log", "$scope", "$rootScope", "$timeout", "d3", "LogicTopologyHelper", "Node", "Tenant", "Ceilometer", "serviceTopologyConfig", "ChartData", function controller($element, $log, $scope, $rootScope, $timeout, d3, LogicTopologyHelper, Node, Tenant, Ceilometer, serviceTopologyConfig, ChartData) {
+        var _this = this;
+
+        $log.info('Logic Plane');
+
+        var svg;
+        this.selectedInstances = [];
+        this.hideInstanceStats = true;
+
+        var handleSvg = function handleSvg(el) {
+
+          svg = d3.select(el).append('svg').style('width', el.clientWidth + 'px').style('height', el.clientHeight + 'px');
+        };
+
+        ChartData.getLogicTree().then(function (tree) {
+          LogicTopologyHelper.updateTree(svg);
+        });
+
+        $scope.$watch(function () {
+          return _this.selected;
+        }, function (selected) {
+          if (selected) {
+            ChartData.selectSubscriber(selected);
+            LogicTopologyHelper.updateTree(svg);
+          }
+        });
+
+        $rootScope.$on('instance.detail.hide', function () {
+          _this.hideInstanceStats = true;
+          $timeout(function () {
+            _this.selectedInstances = [];
+            ChartData.highlightInstances([]);
+            LogicTopologyHelper.updateTree(svg);
+          }, 500);
+        });
+
+        $rootScope.$on('instance.detail', function (evt, service) {
+          ChartData.getInstanceStatus(service).then(function (instances) {
+            // this.hideInstanceStats = false;
+            // // HACK if array is empty wait for animation
+            // if(instances.length === 0){
+            //   this.hideInstanceStats = true;
+            //   $timeout(() => {
+            //     this.selectedInstances = instances;
+            //   }, 500);
+            // }
+            // else{
+            //   this.selectedInstances = instances;
+            // }
+            LogicTopologyHelper.updateTree(svg);
+          });
+        });
+
+        handleSvg($element[0]);
+        LogicTopologyHelper.setupTree(svg);
+
+        this.openSubscriberModal = function () {
+          _this.subscriberModal = true;
+          $scope.$apply();
+        };
+
+        // listen for subscriber modal event
+        $rootScope.$on('subscriber.modal.open', function () {
+          _this.openSubscriberModal();
+        });
+      }]
+    };
+  });
+})();
+'use strict';
+
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic').directive('diagnosticContainer', function () {
+    return {
+      restrict: 'E',
+      templateUrl: 'templates/diagnostic.tpl.html',
+      controllerAs: 'vm',
+      controller: ["ChartData", "Subscribers", "ServiceRelation", "$rootScope", "$log", function controller(ChartData, Subscribers, ServiceRelation, $rootScope, $log) {
+        var _this = this;
+
+        this.loader = true;
+        this.error = false;
+        Subscribers.query().$promise.then(function (subscribers) {
+          _this.subscribers = subscribers;
+          return ServiceRelation.get();
+        }).then(function (serviceChain) {
+          _this.serviceChain = serviceChain;
+        })['catch'](function (e) {
+          throw new Error(e);
+          _this.error = e;
+        })['finally'](function () {
+          _this.loader = false;
+        });
+
+        $rootScope.$on('subscriber.selected', function (evt, subscriber) {
+          ServiceRelation.getBySubscriber(subscriber).then(function (serviceChain) {
+            _this.serviceChain = serviceChain;
+            ChartData.currentServiceChain = serviceChain;
+            return Subscribers.getWithDevices({ id: subscriber.id }).$promise;
+          }).then(function (subscriber) {
+            _this.selectedSubscriber = subscriber;
+            ChartData.currentSubscriber = subscriber;
+          });
+        });
+      }]
+    };
+  });
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').factory('d3', ["$window", function ($window) {
+    return $window.d3;
+  }]);
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').constant('serviceTopologyConfig', {
+    widthMargin: 20,
+    heightMargin: 30,
+    duration: 750,
+    elWidths: [20, 104, 105, 104, 20], //this is not true
+    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
+    }
+  });
+})();
+'use strict';
+
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic').service('ChartData', ["$rootScope", "$q", "lodash", "Tenant", "Node", "serviceTopologyConfig", "Ceilometer", "Instances", function ($rootScope, $q, lodash, Tenant, Node, serviceTopologyConfig, Ceilometer, Instances) {
+    var _this = 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'
+            }] //subscribers goes here
+          }]
+        }]
+      }]
+    };
+
+    this.getLogicTree = function () {
+      var deferred = $q.defer();
+
+      Node.queryWithInstances().$promise.then(function (computeNodes) {
+        _this.logicTopologyData.children[0].children[0].computeNodes = computeNodes;
+        // LogicTopologyHelper.updateTree(svg);
+        deferred.resolve(_this.logicTopologyData);
+      });
+
+      return deferred.promise;
+    };
+
+    /**
+    * Add Subscriber tag to LAN Network
+    */
+    this.addSubscriberTag = function (tags) {
+      _this.logicTopologyData.children[0].children[0].children[0].subscriberTag = {
+        cTag: tags.c_tag,
+        sTag: tags.s_tag
+      };
+    };
+
+    /**
+    * Add Subscribers to the tree
+    */
+    this.addSubscriber = function (subscriber) {
+      subscriber.children = subscriber.devices;
+
+      // add subscriber to data tree
+      _this.logicTopologyData.children[0].children[0].children[0].children = [subscriber];
+      return _this.logicTopologyData;
+    };
+
+    this.getSubscriberTag = function () {
+      var tags = JSON.parse(_this.currentServiceChain.children[0].tenant.service_specific_attribute);
+      delete tags.creator_id;
+
+      _this.addSubscriberTag(tags);
+      // add tags info to current subscriber
+      _this.currentSubscriber.tags = {
+        cTag: tags.c_tag,
+        sTag: tags.s_tag
+      };
+    };
+
+    this.getSubscriberIP = function () {
+      var ip = JSON.parse(_this.currentServiceChain.children[0].children[0].tenant.service_specific_attribute).wan_container_ip;
+      // const ip = this.currentServiceChain.children[0].children[0].tenant.wan_container_ip;
+      _this.logicTopologyData.children[0].subscriberIP = ip;
+    };
+
+    this.selectSubscriber = function (subscriber) {
+
+      // append the device with to config settings
+      serviceTopologyConfig.elWidths.push(160);
+
+      _this.addSubscriber(angular.copy(subscriber));
+
+      //clean selected instances
+      _this.highlightInstances([]);
+
+      _this.getSubscriberTag();
+      _this.getSubscriberIP();
+    };
+
+    this.highlightInstances = function (instances) {
+
+      var computeNodes = _this.logicTopologyData.children[0].children[0].computeNodes;
+
+      // unselect all
+      computeNodes.map(function (node) {
+        node.instances.map(function (instance) {
+          instance.selected = false;
+          return instance;
+        });
+      });
+
+      lodash.forEach(instances, function (instance) {
+        computeNodes.map(function (node) {
+          node.instances.map(function (d3instance) {
+            if (d3instance.id === instance.id) {
+              // console.log(d3instance, instance);
+              d3instance.selected = true;
+              d3instance.stats = instance.stats; //add stats to d3 node
+              d3instance.container = instance.container; // container info to d3 node
+            }
+            return d3instance;
+          });
+        });
+      });
+    };
+
+    this.getInstanceStatus = function (service) {
+      var deferred = $q.defer();
+
+      var p = undefined;
+
+      // subscriber specific
+      if (_this.currentSubscriber) {
+
+        var attr = undefined;
+        try {
+          attr = JSON.parse(service.tenant.service_specific_attribute);
+        } catch (e) {
+          attr = null;
+        }
+
+        // if no instances are associated to the subscriber
+        if (!attr || !attr.instance_id) {
+          var d = $q.defer();
+          d.resolve([]);
+          p = d.promise;
+        }
+        // if ther is an instance
+        else {
+            (function () {
+              var instance = {};
+              p = Instances.get({ id: attr.instance_id }).$promise.then(function (_instance) {
+                instance = _instance;
+                return Ceilometer.getInstanceStats(instance.instance_uuid);
+              }).then(function (stats) {
+                instance.stats = stats;
+                var containerName = 'vcpe-' + _this.currentSubscriber.tags.sTag + '-' + _this.currentSubscriber.tags.cTag;
+                // append containers
+                instance.container = {
+                  name: containerName
+                };
+
+                // TODO fetch container stats
+                return Ceilometer.getContainerStats(containerName);
+              }).then(function (containerStats) {
+                instance.container.stats = containerStats.stats;
+                instance.container.port = containerStats.port;
+                return [instance];
+              });
+            })();
+          }
+      }
+      // global scope
+      else {
+          var param = {
+            'service_vsg': { kind: 'vCPE' },
+            'service_vbng': { kind: 'vBNG' },
+            'service_volt': { kind: 'vOLT' }
+          };
+
+          p = Tenant.queryVsgInstances(param[service.name]).$promise.then(function (instances) {
+
+            return Ceilometer.getInstancesStats(instances);
+          });
+        }
+
+      p.then(function (instances) {
+        _this.highlightInstances(instances);
+        deferred.resolve(instances);
+      })['catch'](function (e) {
+        deferred.reject(e);
+      });
+
+      return deferred.promise;
+    };
+  }]);
+})();
+angular.module('xos.diagnostic').run(function($location){
+  $location.path('/')
+});
+angular.bootstrap(angular.element('#xosDiagnostic'), ['xos.diagnostic']);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosMcordTopology.js b/xos/core/xoslib/static/js/xosMcordTopology.js
new file mode 100644
index 0000000..daac31a
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosMcordTopology.js
@@ -0,0 +1,509 @@
+//Autogenerated, do not edit!!!
+'use strict';
+
+angular.module('xos.mcordTopology', ['ngResource', 'ngCookies', 'ngLodash', 'ui.router', 'xos.helpers']).config(["$stateProvider", function ($stateProvider) {
+  $stateProvider.state('topology', {
+    url: '/',
+    template: '<m-cord-topology></m-cord-topology>'
+  });
+}]).config(["$httpProvider", function ($httpProvider) {
+  $httpProvider.interceptors.push('NoHyperlinks');
+}]).directive('mCordTopology', function () {
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    template: '',
+    controller: ["$element", "$interval", "XosApi", "lodash", "TopologyElements", "NodeDrawer", function controller($element, $interval, XosApi, lodash, TopologyElements, NodeDrawer) {
+
+      var el = $element[0];
+
+      var nodes = [];
+      var links = [];
+
+      var filterBBU = function filterBBU(instances) {
+        return lodash.filter(instances, function (i) {
+          return i.name.indexOf('BBU') >= 0;
+        });
+      };
+
+      var filterOthers = function filterOthers(instances) {
+        return lodash.filter(instances, function (i) {
+          return i.name.indexOf('MME') >= 0 || i.name.indexOf('SGW') >= 0 || i.name.indexOf('PGW') >= 0;
+        });
+      };
+
+      // retrieving instances list
+      var getData = function getData() {
+
+        nodes = TopologyElements.nodes;
+        links = TopologyElements.links;
+
+        XosApi.Instance_List_GET().then(function (instances) {
+          addBbuNodes(filterBBU(instances));
+          addOtherNodes(filterOthers(instances));
+
+          draw(svg, nodes, links);
+        })['catch'](function (e) {
+          throw new Error(e);
+        });
+      };
+
+      var force = d3.layout.force();
+
+      // create svg elements
+      var svg = d3.select(el).append('svg').style('width', el.clientWidth + 'px').style('height', el.clientHeight + 'px');
+
+      var linkContainer = svg.append('g').attr({
+        'class': 'link-container'
+      });
+
+      var nodeContainer = svg.append('g').attr({
+        'class': 'node-container'
+      });
+
+      // replace human readable ids with d3 ids
+      // NOTE now ids are not manatined on update...
+      var buildLinks = function buildLinks(links, nodes) {
+        return links.map(function (l) {
+
+          var source = lodash.findIndex(nodes, { id: l.source });
+          var target = lodash.findIndex(nodes, { id: l.target });
+          // console.log(`link-${source}-${target}`, source, target);
+          return {
+            source: source,
+            target: target,
+            value: 1,
+            id: 'link-' + source + '-' + target,
+            type: l.source.indexOf('fabric') >= 0 ? 'big' : 'small'
+          };
+        });
+      };
+
+      // find fabric nodes and center horizontally
+      var positionFabricNodes = function positionFabricNodes(nodes) {
+        return lodash.map(nodes, function (n) {
+          if (n.type !== 'fabric') {
+            return n;
+          }
+
+          n.x = n.x * hStep;
+          n.y = n.y * vStep;
+
+          return n;
+        });
+      };
+
+      var addBbuNodes = function addBbuNodes(instances) {
+
+        // calculate bbu hStep
+        var bbuHStep = el.clientWidth / 2 / (instances.length + 1);
+
+        // create nodes
+        var bbuNodes = instances.map(function (n, i) {
+          return {
+            type: 'bbu',
+            name: n.name,
+            id: 'bbu-' + n.id,
+            fixed: true,
+            y: vStep * 3,
+            x: bbuHStep * (i + 1)
+          };
+        });
+
+        // create links
+        var bbuLinks = bbuNodes.map(function (n) {
+          return {
+            source: n.id,
+            target: 'fabric2'
+          };
+        });
+
+        // fake RRU nodes and links
+        instances.forEach(function (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
+      var addOtherNodes = function addOtherNodes(instances) {
+        var hStep = el.clientWidth / 2 / (instances.length + 1);
+
+        // create nodes
+        var otherNodes = instances.map(function (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
+        var otherLinks = otherNodes.map(function (n) {
+          return {
+            source: n.id,
+            target: 'fabric4'
+          };
+        });
+
+        nodes = nodes.concat(otherNodes);
+        links = links.concat(otherLinks);
+      };
+
+      var hStep = undefined,
+          vStep = undefined;
+
+      hStep = el.clientWidth / 3;
+      vStep = el.clientHeight / 5;
+
+      var draw = function draw(svg, nodes, links) {
+
+        hStep = el.clientWidth / 3;
+        vStep = el.clientHeight / 5;
+
+        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();
+
+        var linkContainer = d3.select('.link-container');
+        var nodeContainer = d3.select('.node-container');
+
+        NodeDrawer.drawFabricBox(nodeContainer, hStep, vStep);
+
+        // draw links
+        var link = linkContainer.selectAll('.link').data(links, function (d) {
+          return d.id;
+        });
+
+        link.enter().append('line').attr({
+          // class: 'link',
+          id: function id(d) {
+            return d.id;
+          },
+          opacity: 0,
+          'class': function _class(d) {
+            return 'link ' + d.type;
+          }
+        }).transition().duration(1000)
+        // .delay((d, i) => 50 * i)
+        .attr({
+          opacity: 1
+        });
+
+        link.exit().remove();
+
+        //draw nodes
+        var node = nodeContainer.selectAll('.node').data(nodes, function (d) {
+          return d.id;
+        });
+
+        // append a group for any new node
+        var enter = node.enter().append('g', function (d) {
+          return d.interfaceCfgIdentifier;
+        }).attr({
+          'class': function _class(d) {
+            return d.type + ' node';
+          },
+          transform: function transform(d) {
+            return 'translate(' + d.x + ', ' + d.y + ')';
+          }
+        });
+
+        // draw nodes
+        NodeDrawer.drawBbus(enter.filter('.bbu'));
+        NodeDrawer.drawRrus(enter.filter('.rru'));
+        NodeDrawer.drawFabric(enter.filter('.fabric'));
+        NodeDrawer.drawOthers(enter.filter(function (d) {
+          return d.type === 'MME' || d.type === 'SGW' || d.type === 'PGW';
+        }));
+
+        // remove nodes
+        var exit = node.exit();
+
+        NodeDrawer.removeElements(exit);
+
+        force.on('tick', function () {
+          link.attr('x1', function (d) {
+            return d.source.x;
+          }).attr('y1', function (d) {
+            return d.source.y;
+          }).attr('x2', function (d) {
+            return d.target.x;
+          }).attr('y2', function (d) {
+            return d.target.y;
+          });
+
+          node.attr('transform', function (d) {
+            return 'translate(' + d.x + ',' + d.y + ')';
+          });
+        });
+      };
+
+      $interval(function () {
+        getData();
+      }, 5000);
+      getData();
+    }]
+  };
+});
+'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'
+  }],
+  icons: {
+    bbu: 'M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5v65a5,5,0,0,1-5,5zM14,22.5l11-11a10,3,0,0,1,10-2h40a10,3,0,0,1,10,2l11,11zM16,35a5,5,0,0,1,10,0a5,5,0,0,1-10,0z',
+    'switch': 'M10,20a10,10,0,0,1,10-10h70a10,10,0,0,1,10,10v70a10,10,\n            0,0,1-10,10h-70a10,10,0,0,1-10-10zM60,26l12,0,0-8,18,13-18,13,0\n            -8-12,0zM60,60l12,0,0-8,18,13-18,13,0-8-12,0zM50,40l-12,0,0-8\n            -18,13,18,13,0-8,12,0zM50,74l-12,0,0-8-18,13,18,13,0-8,12,0z',
+    rru: 'M85,71.2c-8.9,10.5-29.6,8.7-45.3-3.5C23.9,55.4,19.8,37,28.6,26.5C29.9,38.6,71.5,69.9,85,71.2z M92.7,76.2M16.2,15 M69.5,100.7v-4c0-1.4-1.2-2.2-2.6-2.2H19.3c-1.4,0-2.8,0.7-2.8,2.2v3.9c0,0.7,0.8,1,1.5,1h50.3C69,101.5,69.5,101.3,69.5,100.7z M77.3,7.5l0,3.7c9,0.1,16.3,7.1,16.2,15.7l3.9,0C97.5,16.3,88.5,7.6,77.3,7.5z M77.6,14.7l0,2.5c5.3,0,9.7,4.2,9.6,9.3l2.6,0C89.9,20,84.4,14.7,77.6,14.7z M82.3,22.2c-1.3-1.2-2.9-1.9-4.7-1.9l0,1.2c1.4,0,2.8,0.6,3.8,1.5c1,1,1.6,2.3,1.6,3.7l1.3,0C84.3,25.1,83.6,23.4,82.3,22.2z M38.9,69.5l-5.1,23h16.5l-2.5-17.2C44.1,73.3,38.9,69.5,38.9,69.5zM58.1,54.1c13.7,10.1,26.5,16.8,29.2,13.7c2.7-3.1-5.6-13-19.3-24.4 M62.9,34.2 M62,37.9C47.7,27.3,33.7,20,31,23.1c-2.7,3.2,7,14.2,20.6,26 M73.9,25.7c-2.9,0.1-5.2,2.3-5.1,4.8c0,0.7,0.2,1.4,0.6,2l0,0L53.8,49.7l3.3,2.5L72.7,35l-0.4-0.3c0.6,0.2,1.3,0.3,1.9,0.3c2.9-0.1,5.2-2.3,5.1-4.9C79.3,27.6,76.8,25.6,73.9,25.7z'
+  }
+});
+'use strict';
+
+angular.module('xos.mcordTopology').service('NodeDrawer', ["TopologyElements", function (TopologyElements) {
+
+  var duration = 500;
+
+  var isFabricDrawed = false;
+
+  this.drawFabricBox = function (svg, hStep, vStep) {
+
+    if (isFabricDrawed) {
+      return;
+    }
+
+    var fabric = svg.append('g').attr({
+      transform: 'translate(' + (hStep - 25) + ', ' + (vStep - 25) + ')'
+    });
+
+    fabric.append('rect').attr({
+      width: hStep + 50,
+      height: vStep + 50,
+      'class': 'fabric-container'
+    });
+
+    fabric.append('text').text('Fabric').attr({
+      'text-anchor': 'middle',
+      x: (hStep + 50) / 2,
+      y: -10
+    });
+
+    isFabricDrawed = true;
+  };
+
+  this.drawBbus = function (nodes) {
+
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 15,
+    //     opacity: 1
+    //   });
+    nodes.append('path').attr({
+      'class': function _class(d) {
+        return d.type + ' antenna';
+      },
+      opacity: 0,
+      d: function d() {
+        return TopologyElements.icons.bbu;
+      },
+      transform: 'translate(-22, -22), scale(0.4)'
+    }).transition().duration(duration).attr({
+      opacity: 1
+    });
+
+    nodes.append('text').attr({
+      'text-anchor': 'start',
+      y: 13,
+      x: -14,
+      opacity: 0
+    }).text(function (d) {
+      return 'BBU ' + d.name.substr(d.name.length - 1, 1);
+    }).transition().duration(duration * 2).attr({
+      opacity: 1
+    });
+  };
+
+  this.drawRrus = function (nodes) {
+
+    nodes.append('circle').attr({
+      'class': function _class(d) {
+        return d.type + '-shadow';
+      },
+      r: 0,
+      opacity: 0
+    }).transition().duration(duration * 2)
+    // .delay((d, i) => i * (duration / 2))
+    .attr({
+      r: 40,
+      opacity: 1
+    });
+
+    nodes.append('path').attr({
+      'class': function _class(d) {
+        return d.type + ' antenna';
+      },
+      opacity: 0,
+      d: function d() {
+        return TopologyElements.icons.rru;
+      },
+      transform: 'translate(-22, -22), scale(0.4)'
+    }).transition().duration(duration).attr({
+      opacity: 1
+    });
+
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 10,
+    //     opacity: 1
+    //   });
+  };
+
+  this.drawFabric = function (nodes) {
+    nodes.append('rect').attr({
+      width: 30,
+      height: 30,
+      x: -15,
+      y: -15
+    });
+
+    nodes.append('path').attr({
+      'class': function _class(d) {
+        return d.type;
+      },
+      opacity: 0,
+      d: function d() {
+        return TopologyElements.icons['switch'];
+      },
+      transform: 'translate(-22, -22), scale(0.4)'
+    }).transition().duration(duration)
+    // .delay((d, i) => i * (duration / 2))
+    .attr({
+      opacity: 1
+    });
+  };
+
+  this.drawOthers = function (nodes) {
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 15,
+    //     opacity: 1
+    //   });
+    nodes.append('path').attr({
+      'class': function _class(d) {
+        return d.type + ' antenna';
+      },
+      opacity: 0,
+      d: function d() {
+        return TopologyElements.icons.bbu;
+      },
+      transform: 'translate(-22, -22), scale(0.4)'
+    }).transition().duration(duration).attr({
+      opacity: 1
+    });
+
+    nodes.append('text').attr({
+      'text-anchor': 'start',
+      y: 13,
+      x: -12,
+      opacity: 0
+    }).text(function (d) {
+      return d.type;
+    }).transition().duration(duration * 2).attr({
+      opacity: 1
+    });
+  };
+
+  this.removeElements = function (nodes) {
+    nodes.transition().duration(duration).attr({
+      opacity: 0
+    }).remove();
+  };
+}]);
+angular.module('xos.mcordTopology').run(function($location){$location.path('/')});
+angular.bootstrap(angular.element('#xosMcordTopology'), ['xos.mcordTopology']);
\ No newline at end of file
diff --git a/xos/model_autodeletion.py b/xos/model_autodeletion.py
index 2bfc48c..6eaf63c 100644
--- a/xos/model_autodeletion.py
+++ b/xos/model_autodeletion.py
@@ -1 +1 @@
-ephemeral_models = ['ReservedResource','Instance','Image','Network','Port','Tag','SitePrivilege','SliceMembership','SliceTag','Reservation','Slice']
+ephemeral_models = ['ReservedResource','Instance','Image','Network','Tag','SitePrivilege','SliceMembership','SliceTag','Reservation','Slice']
diff --git a/xos/services/__init__.py b/xos/services/__init__.py
index 8b13789..e69de29 100644
--- a/xos/services/__init__.py
+++ b/xos/services/__init__.py
@@ -1 +0,0 @@
-
diff --git a/xos/services/ceilometer/migrations/0001_initial.py b/xos/services/ceilometer/migrations/0001_initial.py
new file mode 100644
index 0000000..6a3dd15
--- /dev/null
+++ b/xos/services/ceilometer/migrations/0001_initial.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='CeilometerService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'Ceilometer Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='MonitoringChannel',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+        migrations.CreateModel(
+            name='SFlowService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'sFlow Collection Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='SFlowTenant',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenant',),
+        ),
+    ]
diff --git a/xos/services/ceilometer/migrations/__init__.py b/xos/services/ceilometer/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/ceilometer/migrations/__init__.py
diff --git a/xos/services/ceilometer/models.py b/xos/services/ceilometer/models.py
index 42734de..2684097 100644
--- a/xos/services/ceilometer/models.py
+++ b/xos/services/ceilometer/models.py
@@ -35,6 +35,10 @@
         proxy = True
 
     KIND = CEILOMETER_KIND
+    LOOK_FOR_IMAGES=[ "trusty-server-multi-nic-docker", # CloudLab
+                      "trusty-server-multi-nic",
+                    ]
+
 
     sync_attributes = ("private_ip", "private_mac",
                        "ceilometer_ip", "ceilometer_mac",
diff --git a/xos/services/ceilometer/templates/ceilometeradmin.html b/xos/services/ceilometer/templates/ceilometeradmin.html
index 8149666..40f57e8 100644
--- a/xos/services/ceilometer/templates/ceilometeradmin.html
+++ b/xos/services/ceilometer/templates/ceilometeradmin.html
@@ -1,6 +1,6 @@
-<div class = "left-nav">
-<ul>
-<li><a href="/admin/ceilometer/monitoringchannel/">Monitoring Channels</a></li>
-</ul>
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/ceilometer/monitoringchannel/">Monitoring Channels</a>
+    </div>
 </div>
 
diff --git a/xos/services/ceilometer/templates/sflowadmin.html b/xos/services/ceilometer/templates/sflowadmin.html
index da2a8dd..3cbb333 100644
--- a/xos/services/ceilometer/templates/sflowadmin.html
+++ b/xos/services/ceilometer/templates/sflowadmin.html
@@ -1,6 +1,6 @@
-<div class = "left-nav">
-<ul>
-<li><a href="/admin/ceilometer/sflowtenant/">sFlow Tenants</a></li>
-</ul>
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/ceilometer/sflowtenant/">sFlow Tenants</a>
+    </div>
 </div>
 
diff --git a/xos/services/cord/admin.py b/xos/services/cord/admin.py
index 71cae5f..76b505c 100644
--- a/xos/services/cord/admin.py
+++ b/xos/services/cord/admin.py
@@ -104,6 +104,10 @@
     bbs_server = forms.CharField(required=False)
     backend_network_label = forms.CharField(required=False)
     bbs_slice = forms.ModelChoiceField(queryset=Slice.objects.all(), required=False)
+    wan_container_gateway_ip = forms.CharField(required=False)
+    wan_container_gateway_mac = forms.CharField(required=False)
+    wan_container_netbits = forms.CharField(required=False)
+    dns_servers = forms.CharField(required=False)
 
     def __init__(self,*args,**kwargs):
         super (VSGServiceForm,self ).__init__(*args,**kwargs)
@@ -113,6 +117,10 @@
             self.fields['bbs_server'].initial = self.instance.bbs_server
             self.fields['backend_network_label'].initial = self.instance.backend_network_label
             self.fields['bbs_slice'].initial = self.instance.bbs_slice
+            self.fields['wan_container_gateway_ip'].initial = self.instance.wan_container_gateway_ip
+            self.fields['wan_container_gateway_mac'].initial = self.instance.wan_container_gateway_mac
+            self.fields['wan_container_netbits'].initial = self.instance.wan_container_netbits
+            self.fields['dns_servers'].initial = self.instance.dns_servers
 
     def save(self, commit=True):
         self.instance.bbs_api_hostname = self.cleaned_data.get("bbs_api_hostname")
@@ -120,6 +128,10 @@
         self.instance.bbs_server = self.cleaned_data.get("bbs_server")
         self.instance.backend_network_label = self.cleaned_data.get("backend_network_label")
         self.instance.bbs_slice = self.cleaned_data.get("bbs_slice")
+        self.instance.wan_container_gateway_ip = self.cleaned_data.get("wan_container_gateway_ip")
+        self.instance.wan_container_gateway_mac = self.cleaned_data.get("wan_container_gateway_mac")
+        self.instance.wan_container_netbits = self.cleaned_data.get("wan_container_netbits")
+        self.instance.dns_servers = self.cleaned_data.get("dns_servers")
         return super(VSGServiceForm, self).save(commit=commit)
 
     class Meta:
@@ -127,14 +139,16 @@
 
 class VSGServiceAdmin(ReadOnlyAwareAdmin):
     model = VSGService
-    verbose_name = "vCPE Service"
-    verbose_name_plural = "vCPE Service"
+    verbose_name = "vSG Service"
+    verbose_name_plural = "vSG Service"
     list_display = ("backend_status_icon", "name", "enabled")
     list_display_links = ('backend_status_icon', 'name', )
     fieldsets = [(None,             {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", "service_specific_attribute",],
                                      'classes':['suit-tab suit-tab-general']}),
                  ("backend config", {'fields': [ "backend_network_label", "bbs_api_hostname", "bbs_api_port", "bbs_server", "bbs_slice"],
-                                     'classes':['suit-tab suit-tab-backend']}) ]
+                                     'classes':['suit-tab suit-tab-backend']}),
+                 ("vSG config", {'fields': [ "wan_container_gateway_ip", "wan_container_gateway_mac", "wan_container_netbits", "dns_servers"],
+                                     'classes':['suit-tab suit-tab-vsg']}) ]
     readonly_fields = ('backend_status_text', "service_specific_attribute")
     inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
     form = VSGServiceForm
@@ -145,6 +159,7 @@
 
     suit_form_tabs =(('general', 'Service Details'),
         ('backend', 'Backend Config'),
+        ('vsg', 'vSG Config'),
         ('administration', 'Administration'),
         #('tools', 'Tools'),
         ('slices','Slices'),
@@ -164,6 +179,7 @@
     instance = forms.ModelChoiceField(queryset=Instance.objects.all(),required=False)
     last_ansible_hash = forms.CharField(required=False)
     wan_container_ip = forms.CharField(required=False)
+    wan_container_mac = forms.CharField(required=False)
 
     def __init__(self,*args,**kwargs):
         super (VSGTenantForm,self ).__init__(*args,**kwargs)
@@ -176,6 +192,7 @@
             self.fields['instance'].initial = self.instance.instance
             self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
             self.fields['wan_container_ip'].initial = self.instance.wan_container_ip
+            self.fields['wan_container_mac'].initial = self.instance.wan_container_mac
         if (not self.instance) or (not self.instance.pk):
             # default fields for an 'add' form
             self.fields['kind'].initial = VCPE_KIND
@@ -196,9 +213,9 @@
     list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
     list_display_links = ('backend_status_icon', 'id')
     fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id', # 'service_specific_attribute',
-                                     'wan_container_ip', 'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
+                                     'wan_container_ip', 'wan_container_mac', 'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
                           'classes':['suit-tab suit-tab-general']})]
-    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account')
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account', 'wan_container_ip', 'wan_container_mac')
     form = VSGTenantForm
 
     suit_form_tabs = (('general','Details'),)
diff --git a/xos/services/cord/migrations/0001_initial.py b/xos/services/cord/migrations/0001_initial.py
new file mode 100644
index 0000000..3651371
--- /dev/null
+++ b/xos/services/cord/migrations/0001_initial.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='CordSubscriberRoot',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.subscriber',),
+        ),
+        migrations.CreateModel(
+            name='VBNGService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'vBNG Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='VBNGTenant',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenant',),
+        ),
+        migrations.CreateModel(
+            name='VOLTService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'vOLT Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='VOLTTenant',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenant',),
+        ),
+        migrations.CreateModel(
+            name='VSGService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'vSG Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='VSGTenant',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+    ]
diff --git a/xos/services/cord/migrations/__init__.py b/xos/services/cord/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/cord/migrations/__init__.py
diff --git a/xos/services/cord/models.py b/xos/services/cord/models.py
index 2f29d81..37ee78e 100644
--- a/xos/services/cord/models.py
+++ b/xos/services/cord/models.py
@@ -399,7 +399,11 @@
     simple_attributes = ( ("bbs_api_hostname", None),
                           ("bbs_api_port", None),
                           ("bbs_server", None),
-                          ("backend_network_label", "hpc_client"), )
+                          ("backend_network_label", "hpc_client"),
+                          ("wan_container_gateway_ip", ""),
+                          ("wan_container_gateway_mac", ""),
+                          ("wan_container_netbits", "24"),
+                          ("dns_servers", "8.8.8.8") )
 
     def __init__(self, *args, **kwargs):
         super(VSGService, self).__init__(*args, **kwargs)
@@ -598,13 +602,16 @@
         else:
             raise Exception("wan_container_ip.setter called on non-VTN CORD")
 
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
     # Generate the MAC for the container interface connected to WAN
     @property
     def wan_container_mac(self):
         if not self.wan_container_ip:
             return None
-        (a, b, c, d) = self.wan_container_ip.split('.')
-        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+        return self.ip_to_mac(self.wan_container_ip)
 
     @property
     def private_ip(self):
@@ -727,6 +734,10 @@
         if not self.volt:
             raise XOSConfigurationError("This vCPE container has no volt")
 
+        if self.instance:
+            # We're good.
+            return
+
         instance = self.find_or_make_instance_for_s_tag(self.volt.s_tag)
         self.instance = instance
         super(TenantWithContainer, self).save()
@@ -753,23 +764,31 @@
                 self.bbs_account = None
                 super(VSGTenant, self).save()
 
+    def get_wan_address_from_pool(self):
+        ap = AddressPool.objects.filter(name="public_addresses")
+        if not ap:
+            raise Exception("AddressPool 'public_addresses' does not exist. Please configure it.")
+        ap = ap[0]
+
+        addr = ap.get_address()
+        if not addr:
+            raise Exception("AddressPool 'public_addresses' has run out of addresses.")
+        return addr
+
+    def put_wan_address_to_pool(self, addr):
+        AddressPool.objects.filter(name="public_addresses")[0].put_address(addr)
+
     def manage_wan_container_ip(self):
         if CORD_USE_VTN:
             if not self.wan_container_ip:
-                ap = AddressPool.objects.filter(name="public_addresses")
-                if not ap:
-                    raise Exception("AddressPool 'public_addresses' does not exist. Please configure it.")
-                ap = ap[0]
-
-                addr = ap.get_address()
-                if not addr:
-                    raise Exception("AddressPool 'public_addresses' has run out of addresses.")
+                addr = self.get_wan_address_from_pool()
 
                 self.wan_container_ip = addr
+                super(TenantWithContainer, self).save()
 
     def cleanup_wan_container_ip(self):
         if CORD_USE_VTN and self.wan_container_ip:
-            AddressPool.objects.filter(name="public_addresses")[0].put_address(self.wan_container_ip)
+            self.put_wan_address_to_pool(self.wan_container_ip)
             self.wan_container_ip = None
 
     def find_or_make_port(self, instance, network, **kwargs):
@@ -830,6 +849,15 @@
                     tag = Tag(service=self.provider_service, content_object=instance, name="s_tag", value=self.volt.s_tag)
                     tag.save()
 
+            # VTN-CORD needs a WAN address for the VM, so that the VM can
+            # be configured.
+            if CORD_USE_VTN:
+                tags = Tag.select_by_content_object(instance).filter(name="vm_wan_addr")
+                if not tags:
+                    address = self.get_wan_address_from_pool()
+                    tag = Tag(service=self.provider_service, content_object=instance, name="vm_wan_addr", value="%s,%s,%s" % ("public_addresses", address, self.ip_to_mac(address)))
+                    tag.save()
+
     def save(self, *args, **kwargs):
         if not self.creator:
             if not getattr(self, "caller", None):
diff --git a/xos/services/helloworldservice_complete/migrations/0001_initial.py b/xos/services/helloworldservice_complete/migrations/0001_initial.py
new file mode 100644
index 0000000..00279f1
--- /dev/null
+++ b/xos/services/helloworldservice_complete/migrations/0001_initial.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='HelloWorldServiceComplete',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'Hello World Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='HelloWorldTenantComplete',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'Hello World Tenant',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+    ]
diff --git a/xos/services/helloworldservice_complete/migrations/__init__.py b/xos/services/helloworldservice_complete/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/helloworldservice_complete/migrations/__init__.py
diff --git a/xos/services/hpc/migrations/0001_initial.py b/xos/services/hpc/migrations/0001_initial.py
index e1bdd01..38f032c 100644
--- a/xos/services/hpc/migrations/0001_initial.py
+++ b/xos/services/hpc/migrations/0001_initial.py
@@ -2,6 +2,7 @@
 from __future__ import unicode_literals
 
 from django.db import models, migrations
+import core.models.plcorebase
 import django.utils.timezone
 from django.conf import settings
 
@@ -18,13 +19,23 @@
             name='AccessMap',
             fields=[
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
+                ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('name', models.CharField(help_text=b'Name of the Access Map', max_length=64)),
                 ('description', models.TextField(max_length=130, null=True, blank=True)),
                 ('map', models.FileField(help_text=b'specifies which client requests are allowed', upload_to=b'maps/')),
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='CDNPrefix',
@@ -33,8 +44,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('cdn_prefix_id', models.IntegerField(null=True, blank=True)),
                 ('prefix', models.CharField(help_text=b'Registered Prefix for Domain', max_length=200)),
                 ('description', models.TextField(help_text=b'Description of Content Provider', max_length=254, null=True, blank=True)),
@@ -42,7 +58,7 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='ContentProvider',
@@ -51,8 +67,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('content_provider_id', models.IntegerField(null=True, blank=True)),
                 ('name', models.CharField(max_length=254)),
                 ('enabled', models.BooleanField(default=True)),
@@ -60,17 +81,46 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
+        ),
+        migrations.CreateModel(
+            name='HpcHealthCheck',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
+                ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
+                ('kind', models.CharField(default=b'dns', max_length=30, choices=[(b'dns', b'DNS'), (b'http', b'HTTP'), (b'nameserver', b'Name Server')])),
+                ('resource_name', core.models.plcorebase.StrippedCharField(max_length=1024)),
+                ('result_contains', core.models.plcorebase.StrippedCharField(max_length=1024, null=True, blank=True)),
+                ('result_min_size', models.IntegerField(null=True, blank=True)),
+                ('result_max_size', models.IntegerField(null=True, blank=True)),
+            ],
+            options={
+            },
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='HpcService',
             fields=[
                 ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+                ('cmi_hostname', core.models.plcorebase.StrippedCharField(max_length=254, null=True, blank=True)),
+                ('hpc_port80', models.BooleanField(default=True, help_text=b'Enable port 80 for HPC')),
+                ('watcher_hpc_network', core.models.plcorebase.StrippedCharField(help_text=b'Network for hpc_watcher to contact hpc instance', max_length=254, null=True, blank=True)),
+                ('watcher_dnsdemux_network', core.models.plcorebase.StrippedCharField(help_text=b'Network for hpc_watcher to contact dnsdemux instance', max_length=254, null=True, blank=True)),
+                ('watcher_dnsredir_network', core.models.plcorebase.StrippedCharField(help_text=b'Network for hpc_watcher to contact dnsredir instance', max_length=254, null=True, blank=True)),
             ],
             options={
                 'verbose_name': 'HPC Service',
             },
-            bases=('core.service', models.Model),
+            bases=('core.service',),
         ),
         migrations.CreateModel(
             name='OriginServer',
@@ -79,10 +129,15 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('origin_server_id', models.IntegerField(null=True, blank=True)),
-                ('url', models.URLField()),
+                ('url', models.CharField(max_length=1024)),
                 ('authenticated', models.BooleanField(default=False, help_text=b'Status for this Site')),
                 ('enabled', models.BooleanField(default=True, help_text=b'Status for this Site')),
                 ('protocol', models.CharField(default=b'HTTP', max_length=12, choices=[(b'http', b'HTTP'), (b'rtmp', b'RTMP'), (b'rtp', b'RTP'), (b'shout', b'SHOUTcast')])),
@@ -92,7 +147,7 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='ServiceProvider',
@@ -101,30 +156,55 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('service_provider_id', models.IntegerField(null=True, blank=True)),
                 ('name', models.CharField(help_text=b'Service Provider Name', max_length=254)),
                 ('description', models.TextField(help_text=b'Description of Service Provider', max_length=254, null=True, blank=True)),
                 ('enabled', models.BooleanField(default=True)),
+                ('hpcService', models.ForeignKey(to='hpc.HpcService')),
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='SiteMap',
             fields=[
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
+                ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('name', models.CharField(help_text=b'Name of the Site Map', max_length=64)),
                 ('description', models.TextField(max_length=130, null=True, blank=True)),
                 ('map', models.FileField(help_text=b'specifies how to map requests to hpc instances', upload_to=b'maps/')),
+                ('map_id', models.IntegerField(null=True, blank=True)),
+                ('cdnPrefix', models.ForeignKey(blank=True, to='hpc.CDNPrefix', null=True)),
                 ('contentProvider', models.ForeignKey(blank=True, to='hpc.ContentProvider', null=True)),
+                ('hpcService', models.ForeignKey(blank=True, to='hpc.HpcService', null=True)),
                 ('serviceProvider', models.ForeignKey(blank=True, to='hpc.ServiceProvider', null=True)),
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
+        ),
+        migrations.AddField(
+            model_name='hpchealthcheck',
+            name='hpcService',
+            field=models.ForeignKey(blank=True, to='hpc.HpcService', null=True),
+            preserve_default=True,
         ),
         migrations.AddField(
             model_name='contentprovider',
diff --git a/xos/services/mcord/__init__.py b/xos/services/mcord/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/mcord/__init__.py
diff --git a/xos/services/mcord/view.py b/xos/services/mcord/view.py
new file mode 100644
index 0000000..2da4a24
--- /dev/null
+++ b/xos/services/mcord/view.py
@@ -0,0 +1,107 @@
+from django.http import HttpResponse
+from django.views.generic import TemplateView, View
+from django import template
+from core.models import *
+from services.helloworld.models import *
+import json
+import os
+import time
+import tempfile
+
+
+class MCordView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        head_template = self.head_template
+        tail_template = self.tail_template
+
+        title = request.GET.get('service', '')
+        url = "/mcord/?service=%s" % (title)
+
+        form = """
+        <h2 class="content-title">Change %s Service</h2>
+        <div id="content-main">
+            <form class="form-horizontal">
+                <div class="tab-content tab-content-main">
+                    <div class="suit-include suit-tab suit-tab-administration hide">
+                        <div class="left-nav">
+                            <ul>
+                                <li><a href="/admin/ceilometer/monitoringchannel/">Monitoring Channels</a></li>
+                            </ul>
+                        </div>
+                    </div>
+                    <fieldset class="module aligned suit-tab suit-tab-general show">
+                        <div class="panel fieldset-body">
+                            <div class="form-group field-backend_status_text ">
+                                <label class="control-label col-xs-12 col-sm-2"><label>Backend status text:</label></label>
+                                <div class="form-column col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <p><img src="/static/admin/img/icon_clock.gif"> Pending sync, last_status = 0 - Provisioning in progress</p>
+                                </div>
+                            </div>
+                            <div class="form-group field-name ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="required" for="id_name">Name:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_name" maxlength="30" name="name" type="text" value="%s">
+                                    <div class="help-block">Service Name</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-enabled ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="vCheckboxLabel" for="id_enabled">Enabled</label></label>
+                                <div class="form-column widget-CheckboxInput col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input checked="checked" id="id_enabled" name="enabled" type="checkbox">
+                                </div>
+                            </div>
+                            <div class="form-group field-versionNumber ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="required" for="id_versionNumber">VersionNumber:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_versionNumber" maxlength="30" name="versionNumber" type="text">
+                                    <div class="help-block">Version of Service Definition</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-description ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_description">Description:</label></label>
+                                <div class="form-column widget-AdminTextareaWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <textarea class="vLargeTextField form-control" cols="40" id="id_description" maxlength="254" name="description" rows="10"></textarea>
+                                    <div class="help-block">Description of Service</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-view_url ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_view_url">View url:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_view_url" maxlength="1024" name="view_url" type="text" value="%s">
+                                </div>
+                            </div>
+                            <div class="form-group field-icon_url ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_icon_url">Icon url:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_icon_url" maxlength="1024" name="icon_url" type="text">
+                                </div>
+                            </div>
+                        </div>
+                    </fieldset>
+                </div>
+            </form>
+            <div class="form-buttons clearfix">
+                <button type="submit" class="btn btn-high btn-success" name="_save">Save</button>
+                <button type="submit" name="_continue" class=" btn btn-high btn-info">Save and continue editing</button>
+                <button type="submit" name="_addanother" class="btn btn-info">Save and add another</button>
+                <a href="delete/" class="text-error deletelink">Delete</a>
+            </div>
+        </div>
+        """ % (title, title, url)
+
+        t = template.Template(head_template + form + tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs
+        )
diff --git a/xos/services/onos/migrations/0001_initial.py b/xos/services/onos/migrations/0001_initial.py
new file mode 100644
index 0000000..1df9da7
--- /dev/null
+++ b/xos/services/onos/migrations/0001_initial.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ONOSApp',
+            fields=[
+            ],
+            options={
+                'proxy': True,
+            },
+            bases=('core.tenant',),
+        ),
+        migrations.CreateModel(
+            name='ONOSService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'ONOS Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+    ]
diff --git a/xos/services/onos/migrations/__init__.py b/xos/services/onos/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/onos/migrations/__init__.py
diff --git a/xos/services/onos/templates/onosadmin.html b/xos/services/onos/templates/onosadmin.html
index 1e8d42c..e50660e 100644
--- a/xos/services/onos/templates/onosadmin.html
+++ b/xos/services/onos/templates/onosadmin.html
@@ -1,6 +1,6 @@
-<div class = "left-nav">
-<ul>
-<li><a href="/admin/onos/onosapp/">ONOS Apps</a></li>
-</ul>
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/onos/onosapp/">ONOS Apps</a>
+    </div>
 </div>
 
diff --git a/xos/services/requestrouter/migrations/0001_initial.py b/xos/services/requestrouter/migrations/0001_initial.py
index a398283..bdaec7b 100644
--- a/xos/services/requestrouter/migrations/0001_initial.py
+++ b/xos/services/requestrouter/migrations/0001_initial.py
@@ -3,6 +3,7 @@
 
 from django.db import models, migrations
 import django.utils.timezone
+import core.models.plcorebase
 
 
 class Migration(migrations.Migration):
@@ -34,8 +35,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('name', models.SlugField(help_text=b'name of this service map', unique=True)),
                 ('prefix', models.CharField(help_text=b'FQDN of the region of URI space managed by RR on behalf of this service', max_length=256)),
                 ('siteMap', models.FileField(help_text=b'maps client requests to service instances', upload_to=b'maps/', blank=True)),
@@ -45,6 +51,6 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
     ]
diff --git a/xos/services/syndicate_storage/migrations/0001_initial.py b/xos/services/syndicate_storage/migrations/0001_initial.py
index f0065ce..6dd67e8 100644
--- a/xos/services/syndicate_storage/migrations/0001_initial.py
+++ b/xos/services/syndicate_storage/migrations/0001_initial.py
@@ -2,9 +2,10 @@
 from __future__ import unicode_literals
 
 from django.db import models, migrations
-import services.syndicate_storage.models
-import django.utils.timezone
+import core.models.plcorebase
 from django.conf import settings
+import django.utils.timezone
+import services.syndicate_storage.models
 
 
 class Migration(migrations.Migration):
@@ -33,15 +34,20 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('principal_id', models.TextField(unique=True)),
                 ('public_key_pem', models.TextField()),
                 ('sealed_private_key', models.TextField()),
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='SyndicateService',
@@ -61,8 +67,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('name', models.CharField(help_text=b'Human-readable, searchable name of the Volume', max_length=64)),
                 ('description', models.TextField(help_text=b'Human-readable description of what this Volume is used for.', max_length=130, null=True, blank=True)),
                 ('blocksize', models.PositiveIntegerField(help_text=b'Number of bytes per block.')),
@@ -75,7 +86,7 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='VolumeAccessRight',
@@ -84,8 +95,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('cap_read_data', models.BooleanField(default=True, help_text=b'VM can read Volume data')),
                 ('cap_write_data', models.BooleanField(default=True, help_text=b'VM can write Volume data')),
                 ('cap_host_data', models.BooleanField(default=True, help_text=b'VM can host Volume data')),
@@ -94,7 +110,7 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.CreateModel(
             name='VolumeSlice',
@@ -103,8 +119,13 @@
                 ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
                 ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
                 ('enacted', models.DateTimeField(default=None, null=True, blank=True)),
-                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('policed', models.DateTimeField(default=None, null=True, blank=True)),
+                ('backend_register', models.CharField(default=b'{}', max_length=140, null=True)),
+                ('backend_status', models.CharField(default=b'0 - Provisioning in progress', max_length=1024)),
                 ('deleted', models.BooleanField(default=False)),
+                ('write_protect', models.BooleanField(default=False)),
+                ('lazy_blocked', models.BooleanField(default=False)),
+                ('no_sync', models.BooleanField(default=False)),
                 ('cap_read_data', models.BooleanField(default=True, help_text=b'VM can read Volume data')),
                 ('cap_write_data', models.BooleanField(default=True, help_text=b'VM can write Volume data')),
                 ('cap_host_data', models.BooleanField(default=True, help_text=b'VM can host Volume data')),
@@ -116,7 +137,7 @@
             ],
             options={
             },
-            bases=(models.Model,),
+            bases=(models.Model, core.models.plcorebase.PlModelMixIn),
         ),
         migrations.AddField(
             model_name='volume',
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
index a2109ad..04b98df 100644
--- a/xos/synchronizers/base/SyncInstanceUsingAnsible.py
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -147,9 +147,9 @@
 
         fields.update({"keystone_tenant_id": cslice.tenant_id,
                        "keystone_user_id": cuser.kuser_id,
-                       "rabbit_user": instance.controller.rabbit_user,
-                       "rabbit_password": instance.controller.rabbit_password,
-                       "rabbit_host": instance.controller.rabbit_host})
+                       "rabbit_user": getattr(instance.controller,"rabbit_user", None),
+                       "rabbit_password": getattr(instance.controller, "rabbit_password", None),
+                       "rabbit_host": getattr(instance.controller, "rabbit_host", None)})
 
         return fields
 
diff --git a/xos/synchronizers/base/event_loop.py b/xos/synchronizers/base/event_loop.py
index 6cfc9f6..c1b9cda 100644
--- a/xos/synchronizers/base/event_loop.py
+++ b/xos/synchronizers/base/event_loop.py
@@ -421,7 +421,7 @@
 				except Exception,e:
                         		self.consolePrint(bcolors.FAIL + "Model step %r failed" % (sync_step.__name__) + bcolors.ENDC)
 					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (sync_step.__name__, e))
-					logger.log_exc(e)
+					logger.log_exc("Exception in sync step")
 					self.failed_steps.append(S)
 					my_status = STEP_STATUS_KO
 			else:
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
index 6cda511..06403a6 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
+++ b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
@@ -85,6 +85,32 @@
      - remove container
      - start monitoring-channel
 
+#  - name: Start monitoring-channel container
+#    docker:
+#      docker_api_version: "1.18"
+#      name: monitoring-channel-{{ unique_id }}
+#      # was: reloaded
+#      state: running
+#      image: srikanthvavila/monitoring-channel
+#      expose:
+#      - 8000
+#      ports:
+#      - "{{ ceilometer_port }}:8000"
+#      volumes:
+#      - /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config
+#
+#  - name: Get Docker IP
+#    #TODO: copy dockerip.sh to monitoring service synchronizer
+#    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh monitoring-channel-{{ unique_id }}
+#    register: dockerip
+#
+#  - name: Wait for Monitoring channel to come up
+#    wait_for:
+#      host={{ '{{' }} dockerip.stdout {{ '}}' }}
+#      port={{ '{{' }} item {{ '}}' }}
+#      state=present
+#    with_items:
+#    - {{ ceilometer_port }}
 # These are samples, not necessary for correct function of demo
 
   - name: Make sure Monitoring channel service is running
diff --git a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2 b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
index f56c247..ea5b639 100755
--- a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
+++ b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
@@ -22,7 +22,12 @@
 then
     #sudo docker build -t monitoring-channel -f Dockerfile.monitoring_channel .
     sudo docker pull srikanthvavila/monitoring-channel
+if [ -z "$HEADNODEFLATLANIP" ] || [ "$HEADNODEFLATLANIP" == "None" ]
+then
+    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+else
     docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+fi
 else
     docker start $MONITORING_CHANNEL
 fi
diff --git a/xos/synchronizers/openstack/event_loop.py b/xos/synchronizers/openstack/event_loop.py
index 3a14511..db78f07 100644
--- a/xos/synchronizers/openstack/event_loop.py
+++ b/xos/synchronizers/openstack/event_loop.py
@@ -421,7 +421,7 @@
 				except Exception,e:
                         		self.consolePrint(bcolors.FAIL + "Model step %r failed" % (sync_step.__name__) + bcolors.ENDC)
 					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (sync_step.__name__, e))
-					logger.log_exc(e)
+					logger.log_exc("Exception in sync step")
 					self.failed_steps.append(S)
 					my_status = STEP_STATUS_KO
 			else:
diff --git a/xos/synchronizers/openstack/steps/sync_ports.py b/xos/synchronizers/openstack/steps/sync_ports.py
index 3289ece..4f6ce14 100644
--- a/xos/synchronizers/openstack/steps/sync_ports.py
+++ b/xos/synchronizers/openstack/steps/sync_ports.py
@@ -16,8 +16,35 @@
     #     has, and then work backward from each port's network-id to determine
     #     which Network is associated from the port.
 
-    def call(self, **args):
-        logger.info("sync'ing network instances")
+    def call(self, failed=[], deletion=False):
+        if deletion:
+            self.delete_ports()
+        else:
+            self.sync_ports()
+
+    def get_driver(self, port):
+        # We need to use a client driver that specifies the tenant
+        # of the destination instance. Nova-compute will not connect
+        # ports to instances if the port's tenant does not match
+        # the instance's tenant.
+
+        # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
+        # not being in working condition.
+        from openstack.client import OpenStackClient
+        from openstack.driver import OpenStackDriver
+        controller = port.instance.node.site_deployment.controller
+        slice = port.instance.slice
+        caller = port.network.owner.creator
+        auth = {'username': caller.email,
+                'password': caller.remote_password,
+                'tenant': slice.name}
+        client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
+        driver = OpenStackDriver(client=client)
+
+        return driver
+
+    def sync_ports(self):
+        logger.info("sync'ing Ports [delete=False]")
 
         ports = Port.objects.all()
         ports_by_id = {}
@@ -164,21 +191,7 @@
                     logger.info("deferring port %s because controllerNetwork does not have a port-id yet" % port)
                     continue
                 try:
-                    # We need to use a client driver that specifies the tenant
-                    # of the destination instance. Nova-compute will not connect
-                    # ports to instances if the port's tenant does not match
-                    # the instance's tenant.
-
-                    # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
-                    # not being in working condition.
-                    from openstack.client import OpenStackClient
-                    from openstack.driver import OpenStackDriver
-                    caller = port.network.owner.creator
-                    auth = {'username': caller.email,
-                            'password': caller.remote_password,
-                            'tenant': slice.name}
-                    client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
-                    driver = OpenStackDriver(client=client)
+                    driver = self.get_driver(port)
 
                     args = {"network_id": cn.net_id}
                     neutron_port_name = port.get_parameters().get("neutron_port_name", None)
@@ -190,12 +203,28 @@
                     if neutron_port["fixed_ips"]:
                         port.ip = neutron_port["fixed_ips"][0]["ip_address"]
                     port.mac = neutron_port["mac_address"]
+                    port.xos_created = True
+                    logger.info("created neutron port %s for %s" % (port.port_id, port))
                 except:
                     logger.log_exc("failed to create neutron port for %s" % port)
                     continue
                 port.save()
 
-    def delete_record(self, network_instance):
-        # Nothing to do, this is an OpenCloud object
-        pass
+    def delete_ports(self):
+        logger.info("sync'ing Ports [delete=True]")
+        for port in Port.deleted_objects.all():
+            self.delete_record(port)
+
+    def delete_record(self, port):
+        if port.xos_created and port.port_id:
+            logger.info("calling openstack to destroy port %s" % port.port_id)
+            try:
+                driver = self.get_driver(port)
+                driver.shell.quantum.delete_port(port.port_id)
+            except:
+                logger.log_exc("failed to delete port %s from neutron" % port.port_id)
+                return
+
+        logger.info("Purging port %s" % port)
+        port.delete(purge=True)
 
diff --git a/xos/synchronizers/vcpe/run-vtn.sh b/xos/synchronizers/vcpe/run-vtn.sh
new file mode 100755
index 0000000..c4c3b00
--- /dev/null
+++ b/xos/synchronizers/vcpe/run-vtn.sh
@@ -0,0 +1,8 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+cp /root/setup/node_key $XOS_DIR/synchronizers/vcpe/node_key
+chmod 0600 $XOS_DIR/synchronizers/vcpe/node_key
+python vcpe-synchronizer.py  -C $XOS_DIR/synchronizers/vcpe/vtn_vcpe_synchronizer_config
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
index bbb3ad5..5e48837 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
@@ -9,7 +9,7 @@
 from synchronizers.base.syncstep import SyncStep
 from synchronizers.base.ansible import run_template_ssh
 from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
-from core.models import Service, Slice
+from core.models import Service, Slice, Tag
 from services.cord.models import VSGService, VSGTenant, VOLTTenant
 from services.hpc.models import HpcService, CDNPrefix
 from xos.logger import Logger, logging
@@ -25,6 +25,8 @@
 PARENTAL_MECHANISM="dnsmasq"
 ENABLE_QUICK_UPDATE=False
 
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
 class SyncVSGTenant(SyncInstanceUsingAnsible):
     provides=[VSGTenant]
     observes=VSGTenant
@@ -137,6 +139,19 @@
                     if mac:
                         safe_macs.append(mac)
 
+        wan_vm_ip=""
+        wan_vm_mac=""
+        tags = Tag.select_by_content_object(o.instance).filter(name="vm_wan_addr")
+        if tags:
+            parts=tags[0].value.split(",")
+            if len(parts)!=3:
+                raise Exception("vm_wan_addr tag is malformed: %s" % value)
+            wan_vm_ip = parts[1]
+            wan_vm_mac = parts[2]
+        else:
+            if CORD_USE_VTN:
+                raise Exception("no vm_wan_addr tag for instance %s" % o.instance)
+
         fields = {"vlan_ids": vlan_ids,   # XXX remove this
                 "s_tags": s_tags,
                 "c_tags": c_tags,
@@ -145,7 +160,13 @@
                 "bbs_addrs": bbs_addrs,
                 "full_setup": full_setup,
                 "isolation": o.instance.isolation,
-                "safe_browsing_macs": safe_macs}
+                "wan_container_gateway_mac": vcpe_service.wan_container_gateway_mac,
+                "wan_container_gateway_ip": vcpe_service.wan_container_gateway_ip,
+                "wan_container_netbits": vcpe_service.wan_container_netbits,
+                "wan_vm_mac": wan_vm_mac,
+                "wan_vm_ip": wan_vm_ip,
+                "safe_browsing_macs": safe_macs,
+                "dns_servers": [x.strip() for x in vcpe_service.dns_servers.split(",")] }
 
         # add in the sync_attributes that come from the SubscriberRoot object
 
@@ -227,7 +248,10 @@
             if o.instance.isolation in ["container", "container_vm"]:
                 super(SyncVSGTenant, self).run_playbook(o, fields, "sync_vcpetenant_new.yaml")
             else:
-                super(SyncVSGTenant, self).run_playbook(o, fields)
+                if CORD_USE_VTN:
+                    super(SyncVSGTenant, self).run_playbook(o, fields, template_name="sync_vcpetenant_vtn.yaml")
+                else:
+                    super(SyncVSGTenant, self).run_playbook(o, fields)
 
         o.last_ansible_hash = ansible_hash
 
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
index d887547..585f68a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
@@ -33,6 +33,10 @@
         {% for bbs_addr in bbs_addrs %}
         - {{ bbs_addr }}
         {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
       nat_ip: {{ nat_ip }}
       nat_mac: {{ nat_mac }}
       lan_ip: {{ lan_ip }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
index 59047c1..071c30a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
@@ -34,6 +34,10 @@
         {% for bbs_addr in bbs_addrs %}
         - {{ bbs_addr }}
         {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
       nat_ip: {{ nat_ip }}
       nat_mac: {{ nat_mac }}
       lan_ip: {{ lan_ip }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
new file mode 100644
index 0000000..819dcc5
--- /dev/null
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
@@ -0,0 +1,217 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      cdn_enable: {{ cdn_enable }}
+      dnsdemux_ip: {{ dnsdemux_ip }}
+      firewall_enable: {{ firewall_enable }}
+      url_filter_enable: {{ url_filter_enable }}
+      vlan_ids:
+        {% for vlan_id in vlan_ids %}
+        - {{ vlan_id }}
+        {% endfor %}
+      c_tags:
+        {% for c_tag in c_tags %}
+        - {{ c_tag }}
+        {% endfor %}
+      s_tags:
+        {% for s_tag in s_tags %}
+        - {{ s_tag }}
+        {% endfor %}
+      firewall_rules:
+        {% for firewall_rule in firewall_rules.split("\n") %}
+        - {{ firewall_rule }}
+        {% endfor %}
+      cdn_prefixes:
+        {% for prefix in cdn_prefixes %}
+        - {{ prefix }}
+        {% endfor %}
+      bbs_addrs:
+        {% for bbs_addr in bbs_addrs %}
+        - {{ bbs_addr }}
+        {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
+      nat_ip: {{ nat_ip }}
+      nat_mac: {{ nat_mac }}
+      lan_ip: {{ lan_ip }}
+      lan_mac: {{ lan_mac }}
+      wan_ip: {{ wan_ip }}
+      wan_mac: {{ wan_mac }}
+      wan_container_ip: {{ wan_container_ip }}
+      wan_container_netbits: {{ wan_container_netbits }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_container_gateway_ip: {{ wan_container_gateway_ip }}
+      wan_vm_ip: {{ wan_vm_ip }}
+      wan_vm_mac: {{ wan_vm_mac }}
+      wan_next_hop: 10.0.1.253   # FIX ME
+      private_ip: {{ private_ip }}
+      private_mac: {{ private_mac }}
+      hpc_client_ip: {{ hpc_client_ip }}
+      hpc_client_mac: {{ hpc_client_mac }}
+      keystone_tenant_id: {{ keystone_tenant_id }}
+      keystone_user_id: {{ keystone_user_id }}
+      rabbit_user: {{ rabbit_user }}
+      rabbit_password: {{ rabbit_password }}
+      rabbit_host: {{ rabbit_host }}
+      safe_browsing:
+        {% for mac in safe_browsing_macs %}
+        - {{ mac }}
+        {% endfor %}
+
+  tasks:
+  - name: Check to see if network is setup
+    stat: path=/root/network_is_setup
+    register: network_is_setup
+
+  - name: Add eth0.500
+    shell: "{{ '{{' }} item {{ '}}' }}"
+    with_items:
+      - ip link del link eth0 eth0.500 || true
+      - brctl delbr br-wan || true
+      - ip link add link eth0 eth0.500 type vlan id 500
+      - ifconfig eth0.500 up
+      - ifconfig eth0.500 0.0.0.0
+      - ifconfig eth0.500 hw ether {{ wan_vm_mac }}
+      - ip addr add {{ wan_vm_ip }}/{{ wan_container_netbits }} dev eth0.500
+      - ip link set eth0.500 up
+      - ip route del default || true
+      - ip route add default via {{ wan_container_gateway_ip }}
+    when: network_is_setup.stat.exists == False
+
+  - name: install bridge-utils
+    apt: name=bridge-utils state=present
+
+  - name: now redo everything using a bridge
+    shell: "{{ '{{' }} item {{ '}}' }}"
+    with_items:
+       - ip link del link eth0 eth0.500
+       - ip link add link eth0 eth0.500 type vlan id 500
+       - ip link set eth0.500 up
+       - brctl delbr br-wan || true
+       - brctl addbr br-wan
+       - brctl addif br-wan eth0.500
+       - ifconfig br-wan hw ether {{ wan_vm_mac }}
+       - ip addr add {{ wan_vm_ip }}/{{ wan_container_netbits }} dev br-wan
+       - ip link set br-wan up
+       - ip route del default || true
+       - ip route add default via {{ wan_container_gateway_ip }}
+       - ip link set dev br-wan promisc on
+    when: network_is_setup.stat.exists == False
+
+  - name: Remember that the network is setup, so we never do the above again
+    shell: touch /root/network_is_setup
+
+{% if full_setup %}
+  - name: Docker repository
+    copy: src=/opt/xos/synchronizers/vcpe/files/docker.list
+      dest=/etc/apt/sources.list.d/docker.list
+
+  - name: Import the repository key
+    apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
+
+  - name: install Docker
+    apt: name=lxc-docker state=present update_cache=yes
+
+  - name: install python-setuptools
+    apt: name=python-setuptools state=present
+
+  - name: install pip
+    easy_install: name=pip
+
+  - name: install docker-py
+    pip: name=docker-py version=0.5.3
+
+  - name: install Pipework
+    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+       dest=/usr/local/bin/pipework
+       mode=0755
+
+  - name: make sure /etc/dnsmasq.d exists
+    file: path=/etc/dnsmasq.d state=directory owner=root group=root
+
+  - name: Disable resolvconf service
+    shell: service resolvconf stop
+    shell: echo manual > /etc/init/resolvconf.override
+    shell: rm -f /etc/resolv.conf
+
+  - name: Install resolv.conf
+    copy: src=/opt/xos/synchronizers/vcpe/files/vm-resolv.conf
+      dest=/etc/resolv.conf
+
+  - name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
+    shell: pgrep -f [v]cpe_stats_notifier | wc -l
+    register: cron_job_pids_count
+
+#  - name: DEBUG
+#    debug: var=cron_job_pids_count.stdout
+
+#  - name: make sure ~/bin exists
+#    file: path=~/bin state=directory owner=root group=root
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Copy cron job to destination
+#    copy: src=/opt/xos/synchronizers/vcpe/vcpe_stats_notifier.py
+#      dest=/usr/local/sbin/vcpe_stats_notifier.py
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: install python-kombu
+#    apt: name=python-kombu state=present
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Initiate vcpe_stats_notifier cron job
+#    command: sudo python /usr/local/sbin/vcpe_stats_notifier.py --keystone_tenant_id={{ keystone_tenant_id }} --keystone_user_id={{ keystone_user_id }} --rabbit_user={{ rabbit_user }} --rabbit_password={{ rabbit_password }} --rabbit_host={{ rabbit_host }} --vcpeservice_rabbit_exchange='vcpeservice'
+#    async: 9999999999999999
+#    poll: 0
+#    when: cron_job_pids_count.stdout == "0"
+{% endif %}
+
+  - name: vCPE upstart
+    template: src=/opt/xos/synchronizers/vcpe/templates/vcpe.conf.j2 dest=/etc/init/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.conf
+
+  - name: vCPE startup script
+    template: src=/opt/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 dest=/usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh mode=0755
+    notify:
+#    - restart vcpe
+     - stop vcpe
+     - remove container
+     - start vcpe
+
+  - name: create /etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d
+    file: path=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d state=directory owner=root group=root
+
+  - name: vCPE basic dnsmasq config
+    copy: src=/opt/xos/synchronizers/vcpe/files/vcpe.dnsmasq dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/vcpe.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq config
+    template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: Make sure vCPE service is running
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
+  handlers:
+  # Dnsmasq is automatically restarted in the container
+  - name: restart dnsmasq
+    shell: docker exec vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} killall dnsmasq
+
+  - name: restart vcpe
+    shell: service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} stop; sleep 1; service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} start
+
+  - name: stop vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=stopped
+
+  - name: remove container
+    docker: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=absent image=docker-vcpe
+
+  - name: start vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
diff --git a/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 b/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
index c89c762..3682cdf 100644
--- a/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
+++ b/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
@@ -10,5 +10,7 @@
 {% endif %}
 
 # use google's DNS service
-server=8.8.8.8
-server=8.8.4.4
+{% for dns_server in dns_servers %}
+server={{ dns_server }}
+{% endfor %}
+
diff --git a/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 b/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2
new file mode 100644
index 0000000..bf46515
--- /dev/null
+++ b/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+function mac_to_iface {
+    MAC=$1
+    ifconfig|grep $MAC| awk '{print $1}'|grep -v '\.'
+}
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+STAG={{ s_tags[0] }}
+CTAG={{ c_tags[0] }}
+VCPE=vcpe-$STAG-$CTAG
+
+docker inspect $VCPE > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull andybavier/docker-vcpe
+    docker run -d --name=$VCPE --privileged=true --net=none -v /etc/$VCPE/dnsmasq.d:/etc/dnsmasq.d andybavier/docker-vcpe
+else
+    docker start $VCPE
+fi
+
+# Set up networking via pipework
+WAN_IFACE=br-wan
+docker exec $VCPE ifconfig eth0 >> /dev/null || pipework $WAN_IFACE -i eth0 $VCPE {{ wan_container_ip }}/{{ wan_container_netbits }}@{{ wan_container_gateway_ip }} {{ wan_container_mac }}
+
+LAN_IFACE=eth0
+ifconfig $LAN_IFACE >> /dev/null
+if [ "$?" == 0 ]
+then
+    ifconfig $LAN_IFACE.$STAG >> /dev/null || ip link add link $LAN_IFACE name $LAN_IFACE.$STAG type vlan id $STAG
+    ifconfig $LAN_IFACE.$STAG up
+    docker exec $VCPE ifconfig eth1 >> /dev/null || pipework $LAN_IFACE.$STAG -i eth1 $VCPE 192.168.0.1/24 @$CTAG
+fi
+
+#HPC_IFACE=$( mac_to_iface {{ hpc_client_mac }} )
+#docker exec $VCPE ifconfig eth2 >> /dev/null || pipework $HPC_IFACE -i eth2 $VCPE {{ hpc_client_ip }}/24
+
+# Make sure VM's eth0 (hpc_client) has no IP address
+#ifconfig $HPC_IFACE 0.0.0.0
+
+# Now can start up dnsmasq
+docker exec $VCPE service dnsmasq start
+
+# Attach to container
+docker start -a $VCPE
diff --git a/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config b/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
new file mode 100644
index 0000000..e92786b
--- /dev/null
+++ b/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
+steps_dir=/opt/xos/synchronizers/vcpe/steps
+sys_dir=/opt/xos/synchronizers/vcpe/sys
+deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/opt/xos/synchronizers/vcpe/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/vtn/steps/sync_port_addresses.py b/xos/synchronizers/vtn/steps/sync_port_addresses.py
new file mode 100644
index 0000000..6b48911
--- /dev/null
+++ b/xos/synchronizers/vtn/steps/sync_port_addresses.py
@@ -0,0 +1,137 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Port, Controller, Tag
+from core.models.service import COARSE_KIND
+from services.cord.models import VSGTenant
+from services.cord.models import Tenant
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncPortAddresses(SyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vsg tenant to port addresses")
+
+        # build up a dictionary of port-->[wan_addrs] mappings
+        port_addrs = {}
+        for vsg in VSGTenant.get_tenant_objects().all():
+            if not vsg.instance:
+                logger.info("skipping vsg %s because it has no instance" % vsg)
+
+            wan_ip = vsg.wan_container_ip
+            if not wan_ip:
+                logger.info("skipping vsg %s because it has no wan_container_ip" % vsg)
+
+            wan_mac = vsg.wan_container_mac
+            if not wan_mac:
+                logger.info("skipping vsg %s because it has no wan_container_mac" % vsg)
+
+            lan_network = vsg.get_lan_network(vsg.instance)
+            if not lan_network:
+                logger.info("skipping vsg %s because it has no lan_network" % vsg)
+
+            lan_port = Port.objects.filter(instance = vsg.instance, network=lan_network)
+            if not lan_port:
+                logger.info("skipping vsg %s because it has no lan_port" % vsg)
+            lan_port = lan_port[0]
+
+            if not lan_port.port_id:
+                logger.info("skipping vsg %s because its lan_port has no port_id" % vsg)
+
+            if not (lan_port.pk in port_addrs):
+                port_addrs[lan_port.pk] = []
+            entry = {"mac_address": wan_mac, "ip_address": wan_ip}
+            addr_pairs = port_addrs[lan_port.pk]
+            if not entry in addr_pairs:
+                 addr_pairs.append(entry)
+
+            # now do the VM_WAN_IP from the instance
+            if vsg.instance:
+                tags=Tag.select_by_content_object(vsg.instance).filter(name="vm_wan_addr")
+                if tags:
+                    parts=tags[0].value.split(",")
+                    if len(parts)!=3:
+                        raise Exception("vm_wan_addr tag is malformed: %s" % value)
+                    entry = {"mac_address": parts[2], "ip_address": parts[1]}
+                    if not entry in addr_pairs:
+                        addr_pairs.append(entry)
+
+        # Get all ports in all controllers
+        ports_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+        for port_pk in port_addrs.keys():
+            port = Port.objects.get(pk=port_pk)
+            addr_pairs = port_addrs[port_pk]
+            neutron_port = ports_by_id.get(port.port_id,None)
+            if not neutron_port:
+                logger.info("failed to get neutron port for port %s" % port)
+                continue
+
+            ips = [x["ip_address"] for x in addr_pairs]
+
+            changed = False
+
+            # delete addresses in neutron that don't exist in XOS
+            aaps = neutron_port.get("allowed_address_pairs", [])
+            for aap in aaps[:]:
+                if not aap["ip_address"] in ips:
+                    logger.info("removing address %s from port %s" % (aap["ip_address"], port))
+                    aaps.remove(aap)
+                    changed = True
+
+            aaps_ips = [x["ip_address"] for x in aaps]
+
+            # add addresses in XOS that don't exist in neutron
+            for addr in addr_pairs:
+                if not addr["ip_address"] in aaps_ips:
+                    logger.info("adding address %s to port %s" % (addr, port))
+                    aaps.append( addr )
+                    aaps_ips.append(addr["ip_address"])
+                    changed = True
+
+            if changed:
+                logger.info("updating port %s" % port)
+                driver.shell.quantum.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
+
+
+
+
+
+
+
diff --git a/xos/synchronizers/vtn/vtn_synchronizer_config b/xos/synchronizers/vtn/vtn_synchronizer_config
index 302a096..d931839 100644
--- a/xos/synchronizers/vtn/vtn_synchronizer_config
+++ b/xos/synchronizers/vtn/vtn_synchronizer_config
@@ -29,10 +29,16 @@
 deleters_dir=/opt/xos/synchronizers/vtn/deleters
 log_file=console
 #/var/log/hpc.log
-driver=None
+driver=openstack
 pretend=False
 backoff_disabled=True
 
+[nova]
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
 [feefie]
 client_id='vicci_dev_central'
 user_id='pl'
+
+[networking]
+use_vtn=True
diff --git a/xos/tests/README.md b/xos/tests/README.md
new file mode 100644
index 0000000..f3ddad5
--- /dev/null
+++ b/xos/tests/README.md
@@ -0,0 +1,5 @@
+# CORD Tests
+
+The files in this directory are obsolete. The plan is for this
+directory to hold tests in the furture. There are also tests in
+the form of TOSCA specifications in `../configurations/tests`.
diff --git a/xos/tools/apigen/modelgen b/xos/tools/apigen/modelgen
index 72cce08..414540d 100644
--- a/xos/tools/apigen/modelgen
+++ b/xos/tools/apigen/modelgen
@@ -17,6 +17,7 @@
 
 options = None
 
+
 def singular(foo, keys):
 	for k in keys:
 		if (foo==k+'es'):
@@ -28,8 +29,11 @@
 g = globals()
 
 def enum_classes(apps):
+    global app_map
+    app_map = {}
     model_classes = []
     for app in apps:
+            orig_app=app
             app = app + ".models"
             models_module = __import__(app)
             for part in app.split(".")[1:]:
@@ -37,12 +41,15 @@
                     break
                 models_module = getattr(models_module,part)
 
+            global PlCoreBase
             PlCoreBase = getattr(models_module,"PlCoreBase")
 
             for classname in dir(models_module):
                     c = getattr(models_module, classname, None)
                     if type(c)==type(PlCoreBase) and c.__name__ not in options.blacklist:
                             model_classes.append(c)
+                            app_map[c.__name__]=orig_app
+
 
     return model_classes
 
@@ -53,6 +60,8 @@
 	def __init__(self, m):
 		self.model = m
 		self.props = []
+		self.fields = []
+		self.field_dict = []
 		self.refs = []
 		self.plural_name = None
 
@@ -101,11 +110,19 @@
 		return filtered
 
 	def add_object(self, o):
+                global app_map
 		obj = GenObj(o)
 		fields = o._meta.fields
+                try:
+                    obj.app = app_map[o.__name__]
+                except KeyError:
+                    print "KeyError: %r"%o.__name__
+                    pdb.set_trace()
 		self[str(obj).lower()]=obj
 
 	def compute_links(self):
+                base_props = [f.name for f in PlCoreBase._meta.fields]
+
 		for obj in self.values():
 			#if (str(obj)=='network'):
 			#	pdb.set_trace()
@@ -132,7 +149,11 @@
                                         # cause swagger and REST to break
                                         pass
 				else:
-					obj.props.append(f.name)
+                                        f.type = f.__class__.__name__
+
+                                        if (f.name not in base_props):
+                                            obj.fields.append(f) 
+                                        obj.props.append(f.name)
 
 			m2m = obj.model._meta.many_to_many
 			for f in m2m:
diff --git a/xos/tosca/MCORDServiceN.yaml b/xos/tosca/MCORDServiceN.yaml
index bef7bb3..4739d6b 100644
--- a/xos/tosca/MCORDServiceN.yaml
+++ b/xos/tosca/MCORDServiceN.yaml
@@ -22,6 +22,7 @@
       type: tosca.nodes.Service

       requirements:

       properties:

+          view_url: /mcord/?service=vBBU

           kind: mcordservice

 

 

diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index cb0d5ad..e811dd7 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -215,6 +215,18 @@
                 type: string
                 required: false
                 description: Label that matches network used to connect HPC and BBS services.
+            wan_container_gateway_ip:
+                type: string
+                required: false
+            wan_container_gateway_mac:
+                type: string
+                required: false
+            wan_container_netbits:
+                type: string
+                required: false
+            dns_servers:
+                type: string
+                required: false
 
     tosca.nodes.VBNGService:
         derived_from: tosca.nodes.Root
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 81fc1d1..be5ab7d 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -317,6 +317,18 @@
                 type: string
                 required: false
                 description: Label that matches network used to connect HPC and BBS services.
+            wan_container_gateway_ip:
+                type: string
+                required: false
+            wan_container_gateway_mac:
+                type: string
+                required: false
+            wan_container_netbits:
+                type: string
+                required: false
+            dns_servers:
+                type: string
+                required: false
 
     tosca.nodes.VBNGService:
         derived_from: tosca.nodes.Root
diff --git a/xos/tosca/resources/slice.py b/xos/tosca/resources/slice.py
index e2f8991..724957f 100644
--- a/xos/tosca/resources/slice.py
+++ b/xos/tosca/resources/slice.py
@@ -12,7 +12,7 @@
 class XOSSlice(XOSResource):
     provides = "tosca.nodes.Slice"
     xos_model = Slice
-    copyin_props = ["enabled", "description", "slice_url", "max_instances", "default_isolation", "network", "exposed_ports"]
+    copyin_props = ["enabled", "description", "slice_url", "max_instances", "default_isolation", "default_flavor", "network", "exposed_ports"]
 
     def get_xos_args(self):
         args = super(XOSSlice, self).get_xos_args()
diff --git a/xos/tosca/resources/vcpeservice.py b/xos/tosca/resources/vcpeservice.py
index 5c478ac..5c7b2a7 100644
--- a/xos/tosca/resources/vcpeservice.py
+++ b/xos/tosca/resources/vcpeservice.py
@@ -12,5 +12,8 @@
 class XOSVsgService(XOSService):
     provides = "tosca.nodes.VSGService"
     xos_model = VSGService
-    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "private_key_fn", "versionNumber", "backend_network_label"]
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key",
+                    "private_key_fn", "versionNumber", "backend_network_label",
+                    "wan_container_gateway_ip", "wan_container_gateway_mac",
+                    "wan_container_netbits", "dns_servers"]
 
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index 2e4e3a9..a1c2f60 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -9,6 +9,7 @@
 from config import set_override
 config = Config()
 
+
 # Override the config from the environment. This is used leverage the LINK
 # capability of docker. It would be far better to use DNS and that can be
 # done in environments like kubernetes. Look for environment variables that
@@ -20,7 +21,7 @@
     config.db_port = parsed.port
 
 env_to_config_dict = {
-    "XOS_DB_PORT" : overrideDbSettings
+    "XOS_DB_PORT": overrideDbSettings
 }
 
 for key, ofunc in env_to_config_dict.items():
@@ -30,21 +31,21 @@
 GEOIP_PATH = "/usr/share/GeoIP"
 XOS_DIR = "/opt/xos"
 
-DEBUG = False
+DEBUG = True
 TEMPLATE_DEBUG = DEBUG
 
 ADMINS = (
     # ('Your Name', 'your_email@example.com'),
 )
 
-#LOGIN_REDIRECT_URL = '/admin/core/user'
+# LOGIN_REDIRECT_URL = '/admin/core/user'
 LOGIN_REDIRECT_URL = '/admin/loggedin/'
 
 MANAGERS = ADMINS
 
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',  # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
         'NAME': config.db_name,                      # Or path to database file if using sqlite3.
         # The following settings are not used with sqlite3:
         'USER': config.db_user,
@@ -160,7 +161,7 @@
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
-#    'django.contrib.sites',
+    # 'django.contrib.sites',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     # Uncomment the next line to enable the admin:
@@ -185,7 +186,7 @@
     'rest_framework_swagger',
 )
 
-if DJANGO_VERSION[1]>=7:
+if DJANGO_VERSION[1] >= 7:
     # if django >= 1.7, then change the admin module
     INSTALLED_APPS = list(INSTALLED_APPS)
     INSTALLED_APPS[INSTALLED_APPS.index('django.contrib.admin')] = 'django.contrib.admin.apps.SimpleAdminConfig'
diff --git a/xos/xos/urls.py b/xos/xos/urls.py
index 4c3f07d..5a56bcb 100644
--- a/xos/xos/urls.py
+++ b/xos/xos/urls.py
@@ -1,3 +1,4 @@
+import importlib
 from django.conf.urls import patterns, include, url
 
 # Uncomment the next two lines to enable the admin:
@@ -10,26 +11,57 @@
 from core.views.legacyapi import LegacyXMLRPC
 from core.views.serviceGraph import ServiceGridView, ServiceGraphView
 from services.helloworld.view import *
-#from core.views.analytics import AnalyticsAjaxView
+from services.mcord.view import *
+# from core.views.analytics import AnalyticsAjaxView
 from core.models import *
 from rest_framework import generics
 from core.dashboard.sites import SitePlus
 from django.http import HttpResponseRedirect
-#from core.xoslib import XOSLibDataView
+# from core.xoslib import XOSLibDataView
+
+# Django settings for XOS.
+from config import Config
+from config import set_override
+config = Config()
+
+
+def load_class(full_class_string):
+    """
+    dynamically load a class from a string
+    """
+
+    class_data = full_class_string.split(".")
+    module_path = ".".join(class_data[:-1])
+    class_str = class_data[-1]
+
+    module = importlib.import_module(module_path)
+    # Finally, we retrieve the Class
+    return getattr(module, class_str)
+
+servicePage = getattr(config, "gui_service_view_class", ServiceGridView)
+
+if(isinstance(servicePage, basestring)):
+    serviceClass = getattr(load_class(servicePage), "as_view")
+else:
+    serviceClass = getattr(servicePage, "as_view")
 
 admin.site = SitePlus()
 admin.autodiscover()
 
-def redirect_to_apache(request):
-     """ bounce a request back to the apache server that is running on the machine """
-     apache_url = "http://%s%s" % (request.META['HOSTNAME'], request.path)
-     return HttpResponseRedirect(apache_url)
 
-urlpatterns = patterns('',
-    # Examples:
+def redirect_to_apache(request):
+    """ bounce a request back to the apache server that is running on the machine """
+    apache_url = "http://%s%s" % (request.META['HOSTNAME'], request.path)
+    return HttpResponseRedirect(apache_url)
+
+urlpatterns = patterns(
+    '',
     url(r'^observer', 'core.views.observer.Observer', name='observer'),
     url(r'^helloworld', HelloWorldView.as_view(), name='helloWorld'),
-    url(r'^serviceGrid', ServiceGridView.as_view(), name='serviceGrid'),
+
+    url(r'^mcord', MCordView.as_view(), name='mcord'),
+
+    url(r'^serviceGrid', serviceClass(), name='serviceGrid'),
     url(r'^serviceGraph.png', ServiceGraphView.as_view(), name='serviceGraph'),
     url(r'^hpcConfig', 'core.views.hpc_config.HpcConfig', name='hpcConfig'),
 
@@ -41,20 +73,19 @@
     # Uncomment the next line to enable the admin:
     url(r'^admin/', include(admin.site.urls)),
     url(r'^', include(admin.site.urls)),
-    #url(r'^profile/home', 'core.views.home'),
+    # url(r'^profile/home', 'core.views.home'),
 
-#    url(r'^admin/xoslib/(?P<name>\w+)/$', XOSLibDataView.as_view(), name="xoslib"),
+    # url(r'^admin/xoslib/(?P<name>\w+)/$', XOSLibDataView.as_view(), name="xoslib"),
 
     url(r'^xmlrpc/legacyapi/$', 'core.views.legacyapi.LegacyXMLRPC', name='xmlrpc'),
 
-#    url(r'^analytics/(?P<name>\w+)/$', AnalyticsAjaxView.as_view(), name="analytics"),
+    # url(r'^analytics/(?P<name>\w+)/$', AnalyticsAjaxView.as_view(), name="analytics"),
 
     url(r'^files/', redirect_to_apache),
 
-    #Adding in rest_framework urls
+    # Adding in rest_framework urls
     url(r'^xos/', include('rest_framework.urls', namespace='rest_framework')),
 
     # XOSLib rest methods
     url(r'^xoslib/', include('core.xoslib.methods', namespace='xoslib')),
   ) + get_REST_patterns() + get_hpc_REST_patterns()
-