Initial import of Angular5 components services and modules

Change-Id: I3953f1fbf7d5697a1c6d432808dd17d816ec285a
diff --git a/web/gui2/src/main/java b/web/gui2/src/main/java
new file mode 120000
index 0000000..f576aa0
--- /dev/null
+++ b/web/gui2/src/main/java
@@ -0,0 +1 @@
+../../../gui/src/main/java/
\ No newline at end of file
diff --git a/web/gui2/src/main/tsconfig.json b/web/gui2/src/main/tsconfig.json
new file mode 100644
index 0000000..6a9d817
--- /dev/null
+++ b/web/gui2/src/main/tsconfig.json
@@ -0,0 +1,19 @@
+{
+  "compileOnSave": false,
+  "compilerOptions": {
+    "outDir": "./dist/out-tsc",
+    "sourceMap": true,
+    "declaration": false,
+    "moduleResolution": "node",
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "target": "es6",
+    "typeRoots": [
+      "node_modules/@types"
+    ],
+    "lib": [
+      "es2017",
+      "dom"
+    ]
+  }
+}
diff --git a/web/gui2/src/main/tslint.json b/web/gui2/src/main/tslint.json
new file mode 100644
index 0000000..cb6dee5
--- /dev/null
+++ b/web/gui2/src/main/tslint.json
@@ -0,0 +1,143 @@
+{
+  "rulesDirectory": [
+    "../../node_modules/codelyzer"
+  ],
+  "rules": {
+    "arrow-return-shorthand": true,
+    "callable-types": true,
+    "class-name": true,
+    "comment-format": [
+      true,
+      "check-space"
+    ],
+    "curly": true,
+    "deprecation": {
+      "severity": "warn"
+    },
+    "eofline": true,
+    "forin": true,
+    "import-blacklist": [
+      true,
+      "rxjs",
+      "rxjs/Rx"
+    ],
+    "import-spacing": true,
+    "indent": [
+      true,
+      "spaces"
+    ],
+    "interface-over-type-literal": true,
+    "label-position": true,
+    "max-line-length": [
+      true,
+      140
+    ],
+    "member-access": false,
+    "member-ordering": [
+      true,
+      {
+        "order": [
+          "static-field",
+          "instance-field",
+          "static-method",
+          "instance-method"
+        ]
+      }
+    ],
+    "no-arg": true,
+    "no-bitwise": true,
+    "no-console": [
+      true,
+      "debug",
+      "info",
+      "time",
+      "timeEnd",
+      "trace"
+    ],
+    "no-construct": true,
+    "no-debugger": true,
+    "no-duplicate-super": true,
+    "no-empty": false,
+    "no-empty-interface": true,
+    "no-eval": true,
+    "no-inferrable-types": [
+      true,
+      "ignore-params"
+    ],
+    "no-misused-new": true,
+    "no-non-null-assertion": true,
+    "no-shadowed-variable": true,
+    "no-string-literal": false,
+    "no-string-throw": true,
+    "no-switch-case-fall-through": true,
+    "no-trailing-whitespace": true,
+    "no-unnecessary-initializer": true,
+    "no-unused-expression": true,
+    "no-use-before-declare": true,
+    "no-var-keyword": true,
+    "object-literal-sort-keys": false,
+    "one-line": [
+      true,
+      "check-open-brace",
+      "check-catch",
+      "check-else",
+      "check-whitespace"
+    ],
+    "prefer-const": true,
+    "quotemark": [
+      true,
+      "single"
+    ],
+    "radix": true,
+    "semicolon": [
+      true,
+      "always"
+    ],
+    "triple-equals": [
+      true,
+      "allow-null-check"
+    ],
+    "typedef-whitespace": [
+      true,
+      {
+        "call-signature": "nospace",
+        "index-signature": "nospace",
+        "parameter": "nospace",
+        "property-declaration": "nospace",
+        "variable-declaration": "nospace"
+      }
+    ],
+    "unified-signatures": true,
+    "variable-name": false,
+    "whitespace": [
+      true,
+      "check-branch",
+      "check-decl",
+      "check-operator",
+      "check-separator",
+      "check-type"
+    ],
+    "directive-selector": [
+      true,
+      "attribute",
+      "onos",
+      "camelCase"
+    ],
+    "component-selector": [
+      true,
+      "element",
+      "onos",
+      "kebab-case"
+    ],
+    "no-output-on-prefix": true,
+    "use-input-property-decorator": true,
+    "use-output-property-decorator": true,
+    "use-host-property-decorator": true,
+    "no-input-rename": true,
+    "no-output-rename": true,
+    "use-life-cycle-interface": true,
+    "use-pipe-transform-interface": true,
+    "component-class-suffix": true,
+    "directive-class-suffix": true
+  }
+}
diff --git a/web/gui2/src/main/webapp/WEB-INF/web.xml b/web/gui2/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..186f5a6
--- /dev/null
+++ b/web/gui2/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2014-present Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>ONOS GUI 2</display-name>
+
+    <welcome-file-list>
+        <welcome-file>index.html</welcome-file>
+    </welcome-file-list>
+
+    <!--
+    -->
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/index.html</url-pattern>
+        </web-resource-collection>
+        <web-resource-collection>
+            <web-resource-name>Secured API</web-resource-name>
+            <url-pattern>/rs/applications/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+        <!--
+        <user-data-constraint>
+            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+        </user-data-constraint>
+        -->
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>karaf</realm-name>
+        <form-login-config>
+            <form-login-page>/login.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <servlet>
+        <servlet-name>Index Page</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>org.onosproject.ui.impl.MainIndexResource</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Index Page</servlet-name>
+        <url-pattern>/index.html</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>Main Module</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>org.onosproject.ui.impl.MainModuleResource
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Main Module</servlet-name>
+        <url-pattern>/onos.js</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>Nav Module</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>org.onosproject.ui.impl.MainNavResource</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Nav Module</servlet-name>
+        <url-pattern>/nav.html</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>View Module</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>org.onosproject.ui.impl.MainViewResource</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>View Module</servlet-name>
+        <url-pattern>/app/view/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>Foo Module</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>org.onosproject.ui.impl.FooResource</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Foo Module</servlet-name>
+        <url-pattern>/raw/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>jersey.config.server.provider.classnames</param-name>
+            <param-value>
+                org.glassfish.jersey.media.multipart.MultiPartFeature,
+                org.onosproject.ui.impl.LogoutResource,
+                org.onosproject.ui.impl.TopologyResource,
+                org.onosproject.ui.impl.ApplicationResource
+            </param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/rs/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet>
+        <servlet-name>Web Socket Service</servlet-name>
+        <servlet-class>org.onosproject.ui.impl.UiWebSocketServlet
+        </servlet-class>
+        <load-on-startup>2</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Web Socket Service</servlet-name>
+        <url-pattern>/websock/*</url-pattern>
+    </servlet-mapping>
+
+</web-app>
diff --git a/web/gui2/src/main/webapp/app/README.txt b/web/gui2/src/main/webapp/app/README.txt
new file mode 100644
index 0000000..cffc8a1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/README.txt
@@ -0,0 +1,7 @@
+# Main ONOS UI Web Application
+
+../index.html is the main launch point for the application.
+
+fw/ contains framework related code
+
+view/ contains view related code
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/consolelogger.service.ts b/web/gui2/src/main/webapp/app/consolelogger.service.ts
new file mode 100644
index 0000000..1ba88f9
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/consolelogger.service.ts
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { environment } from '../environments/environment';
+import { Logger } from './log.service';
+
+export let isDebugMode = environment.isDebugMode;
+
+const noop = (): any => undefined;
+
+/**
+ * ONOS GUI -- LogService
+ * Inspired by https://robferguson.org/blog/2017/09/09/a-simple-logging-service-for-angular-4/
+ */
+@Injectable()
+export class ConsoleLoggerService implements Logger {
+
+  get debug() {
+    if (isDebugMode) {
+      return console.debug.bind(console);
+    } else {
+      return noop;
+    }
+  }
+
+  get info() {
+    if (isDebugMode) {
+      return console.info.bind(console);
+    } else {
+      return noop;
+    }
+  }
+
+  get warn() {
+    return console.warn.bind(console);
+  }
+
+  get error() {
+    return console.error.bind(console);
+  }
+
+  invokeConsoleMethod(type: string, args?: any): void {
+    const logFn: Function = (console)[type] || console.log || noop;
+    logFn.apply(console, [args]);
+  }
+}
diff --git a/web/gui2/src/main/webapp/app/detectbrowser.directive.ts b/web/gui2/src/main/webapp/app/detectbrowser.directive.ts
new file mode 100644
index 0000000..2c2b335
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/detectbrowser.directive.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { FnService } from './fw/util/fn.service';
+import { LogService } from './log.service';
+import { OnosService } from './onos.service';
+
+/**
+ * ONOS GUI -- Detect Browser Directive
+ */
+@Directive({
+  selector: '[onosDetectBrowser]'
+})
+export class DetectBrowserDirective {
+  constructor(
+    private fs: FnService,
+    private log: LogService,
+    private onos: OnosService
+  ) {
+        log.debug('DetectBrowserDirective constructed');
+
+        const body: HTMLBodyElement = document.getElementsByTagName('body')[0];
+//        let body = d3.select('body');
+        let browser = '';
+        if (fs.isChrome()) {
+            browser = 'chrome';
+        } else if (fs.isSafari()) {
+            browser = 'safari';
+        } else if (fs.isFirefox()) {
+            browser = 'firefox';
+        }
+        body.classList.add(browser);
+//        body.classed(browser, true);
+        this.onos.browser = browser;
+
+        if (fs.isMobile()) {
+            body.classList.add('mobile');
+            this.onos.mobile = true;
+        }
+
+        this.log.debug('Detected browser is', fs.cap(browser));
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts b/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts
new file mode 100644
index 0000000..dcd33b0
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { EditableTextService } from '../layer/editabletext.service';
+import { FnService } from '../util/fn.service';
+import { IconService } from '../svg/icon.service';
+import { LogService } from '../../log.service';
+import { MastService } from '../mast/mast.service';
+import { PanelService } from './panel.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Layer -- Details Panel Service
+ */
+@Injectable()
+export class DetailsPanelService {
+
+  constructor(
+      private etc: EditableTextService,
+      private fs: FnService,
+      private is: IconService,
+      private log: LogService,
+      private mast: MastService,
+      private panel: PanelService,
+      private wss: WebSocketService
+  ) {
+      this.log.debug('DetailsPanelService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/dialog.service.ts b/web/gui2/src/main/webapp/app/fw/layer/dialog.service.ts
new file mode 100644
index 0000000..880e2bd
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/dialog.service.ts
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+
+import { FnService } from '../util/fn.service';
+import { KeyService } from '../util/key.service';
+import { LogService } from '../../log.service';
+import { PanelService } from './panel.service';
+
+/**
+ * ONOS GUI -- Layer -- Dialog Service
+ *
+ * Builds on the panel service to provide dialog functionality.
+ */
+@Injectable()
+export class DialogService {
+
+  constructor(
+    private fs: FnService,
+    private ks: KeyService,
+    private log: LogService,
+    private ps: PanelService,
+  ) {
+    this.log.debug('DialogService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/editabletext.service.ts b/web/gui2/src/main/webapp/app/fw/layer/editabletext.service.ts
new file mode 100644
index 0000000..068e0cc
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/editabletext.service.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { KeyService } from '../util/key.service';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Layer -- Editable Text Service
+ */
+@Injectable()
+export class EditableTextService {
+
+    constructor(
+        private ks: KeyService,
+        private log: LogService,
+        private wss: WebSocketService
+    ) {
+      this.log.debug('EditableTextService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/flash.service.ts b/web/gui2/src/main/webapp/app/fw/layer/flash.service.ts
new file mode 100644
index 0000000..bd71d28
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/flash.service.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Layer -- Flash Service
+ *
+ * Provides a mechanism to flash short informational messages to the screen
+ * to alert the user of something, e.g. "Hosts visible" or "Hosts hidden".
+ */
+@Injectable()
+export class FlashService {
+
+  constructor(
+    private log: LogService
+  ) {
+    this.log.debug('FlashService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/layer.module.ts b/web/gui2/src/main/webapp/app/fw/layer/layer.module.ts
new file mode 100644
index 0000000..f5923fc
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/layer.module.ts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { UtilModule } from '../util/util.module';
+
+import { DetailsPanelService } from './detailspanel.service';
+import { DialogService } from './dialog.service';
+import { EditableTextService } from './editabletext.service';
+import { FlashService } from './flash.service';
+import { LoadingService } from './loading.service';
+import { PanelService } from './panel.service';
+import { QuickHelpService } from './quickhelp.service';
+import { VeilService } from './veil.service';
+
+/**
+ * ONOS GUI -- Layers Module
+ */
+@NgModule({
+  imports: [
+    CommonModule,
+    UtilModule
+  ],
+  providers: [
+    DetailsPanelService,
+    DialogService,
+    EditableTextService,
+    FlashService,
+    LoadingService,
+    PanelService,
+    QuickHelpService,
+    VeilService
+  ]
+})
+export class LayerModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/layer/loading.service.css b/web/gui2/src/main/webapp/app/fw/layer/loading.service.css
new file mode 100644
index 0000000..b787f3b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/loading.service.css
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2015-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Loading Service -- CSS file
+ */
+
+#loading-anim {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    -webkit-transform: translate(-50%, -50%);
+    transform: translate(-50%, -50%);
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts b/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts
new file mode 100644
index 0000000..6c31f15
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts
@@ -0,0 +1,135 @@
+/*
+ *  Copyright 2015-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+import { ThemeService } from '../util/theme.service';
+import { WebSocketService } from '../remote/websocket.service';
+import * as d3 from 'd3';
+
+const id = 'loading-anim';
+const dir = 'data/img/loading/';
+const pfx = '/load-';
+const nImgs = 16;
+const speed = 100;
+const waitDelay = 500;
+
+
+/**
+ * ONOS GUI -- Layer -- Loading Service
+ *
+ * Provides a mechanism to start/stop the loading animation, center screen.
+ */
+@Injectable()
+export class LoadingService {
+    images: any[] = [];
+    idx: number = 0;
+    img: any;
+    theme: string;
+    task: any;
+    wait: number;
+
+    constructor(
+        private fs: FnService,
+        private log: LogService,
+        private ts: ThemeService,
+        private wss: WebSocketService
+    ) {
+        this.preloadImages();
+        this.log.debug('LoadingService constructed');
+    }
+
+    dbg(...args) {
+        this.fs.debug(this.constructor.name, args);
+    }
+
+    preloadImages() {
+        let idx: number;
+
+        this.dbg('preload images start...');
+        for (idx=1; idx<=nImgs; idx++) {
+            this.addImg('light', idx);
+            this.addImg('dark', idx);
+        }
+        this.dbg('preload images DONE!', this.images);
+    }
+
+    addImg(theme: string, idx: number) {
+        let img = new Image();
+        img.src = this.fname(idx, theme);
+        this.images.push(img);
+    }
+
+    fname(i: number, theme: string) {
+        const z = i > 9 ? '' : '0';
+        return dir + theme + pfx + z + i + '.png';
+    }
+
+    nextFrame() {
+        this.idx = this.idx === 16 ? 1 : this.idx + 1;
+        this.img.attr('src', this.fname(this.idx, this.theme));
+    }
+
+    // start displaying 'loading...' animation (idempotent)
+    startAnim() {
+        this.dbg('start ANIMATION');
+        this.theme = this.ts.getTheme();
+        let div = d3.select('#'+id);
+        if (div.empty()) {
+            div = d3.select('body')
+                .append('div')
+                .attr('id', id);
+            this.img = div
+                .append('img')
+                .attr('src', this.fname(1, this.theme));
+            this.idx = 1;
+            this.task = setInterval(() => this.nextFrame(), speed);
+        }
+    }
+
+    // stop displaying 'loading...' animation (idempotent)
+    stopAnim() {
+        this.dbg('*stop* ANIMATION');
+        if (this.task) {
+            clearInterval(this.task);
+            this.task = null;
+        }
+        d3.select('#'+id).remove();
+    }
+
+    // schedule function to start animation in the future
+    start() {
+        this.dbg('start (schedule)');
+        this.wait = setTimeout(this.startAnim(), waitDelay);
+    }
+
+    // cancel future start, if any; stop the animation
+    stop() {
+        if (this.wait) {
+            this.dbg('start CANCELED');
+            clearTimeout(this.wait);
+            this.wait = null;
+        }
+        this.stopAnim();
+    }
+
+    // return true if start() has been called but not stop()
+    waiting() {
+        return !!this.wait;
+    }
+
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/panel.service.ts b/web/gui2/src/main/webapp/app/fw/layer/panel.service.ts
new file mode 100644
index 0000000..7ccb7d9
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/panel.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Layer -- Panel Service
+ */
+@Injectable()
+export class PanelService {
+
+  constructor(
+    private fs: FnService,
+    private log: LogService
+  ) {
+    this.log.debug('PanelService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/quickhelp.service.ts b/web/gui2/src/main/webapp/app/fw/layer/quickhelp.service.ts
new file mode 100644
index 0000000..f433a2b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/quickhelp.service.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LionService } from '../util/lion.service';
+import { LogService } from '../../log.service';
+import { SvgUtilService } from '../svg/svgutil.service';
+
+/**
+ * ONOS GUI -- Layer -- Quick Help Service
+ *
+ * Provides a mechanism to display key bindings and mouse gesture notes.
+ */
+@Injectable()
+export class QuickHelpService {
+
+  constructor(
+    private fs: FnService,
+    private ls: LionService,
+    private log: LogService,
+    private sus: SvgUtilService
+  ) {
+    this.log.debug('QuickhelpService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/layer/veil.service.ts b/web/gui2/src/main/webapp/app/fw/layer/veil.service.ts
new file mode 100644
index 0000000..d755e5d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/layer/veil.service.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { GlyphService } from '../svg/glyph.service';
+import { KeyService } from '../util/key.service';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Layer -- Veil Service
+ *
+ * Provides a mechanism to display an overlaying div with information.
+ * Used mainly for web socket connection interruption.
+ */
+@Injectable()
+export class VeilService {
+
+  constructor(
+    private fs: FnService,
+    private gs: GlyphService,
+    private ks: KeyService,
+    private log: LogService,
+    private wss: WebSocketService
+  ) {
+      this.log.debug('VeilService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast.module.ts b/web/gui2/src/main/webapp/app/fw/mast/mast.module.ts
new file mode 100644
index 0000000..99c986d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast.module.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SvgModule } from '../svg/svg.module';
+
+import { MastComponent } from './mast/mast.component';
+
+import { MastService } from './mast.service';
+
+/**
+ * ONOS GUI -- Masthead Module
+ */
+@NgModule({
+  imports: [
+    CommonModule,
+    SvgModule // For the IconComponent
+  ],
+  declarations: [
+    MastComponent
+  ],
+  exports: [
+    MastComponent
+  ],
+  providers: [
+    MastService
+  ]
+})
+export class MastModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast.service.ts b/web/gui2/src/main/webapp/app/fw/mast/mast.service.ts
new file mode 100644
index 0000000..d357458
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast.service.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+const padMobile = 16;
+
+/**
+ * ONOS GUI -- Masthead Service
+ */
+@Injectable()
+export class MastService {
+
+  public mastHeight = 48;
+
+  constructor(
+    private fs: FnService,
+    private log: LogService
+  ) {
+    if (this.fs.isMobile()) {
+        this.mastHeight += padMobile;
+    }
+
+    this.log.debug('MastService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.css b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.css
new file mode 100644
index 0000000..b5f1e5f
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.css
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Masthead (layout) -- CSS file
+ */
+
+#mast {
+    height: 48px;
+    padding: 0;
+}
+
+#mast a:hover {
+    text-decoration: none;
+}
+
+html[data-platform='iPad'] #mast {
+    padding-top: 16px;
+}
+
+#mast .nav-menu-button {
+    display: inline-block;
+    vertical-align: middle;
+    text-align: center;
+    line-height: 48px;
+    padding: 0 12px;
+    cursor: pointer; cursor: hand;
+    /* Needed to removed 3px space at the bottom of img tags */
+    font-size: 0;
+}
+
+#mast .nav-menu-button img {
+    width: 25px;
+    vertical-align: middle;
+}
+
+#mast .logo {
+    height: 47px;
+    width: 511px;
+    vertical-align: bottom;
+}
+
+#mast-right {
+    display: inline-block;
+    float: right;
+    position: relative;
+    top: 0;
+    padding-right: 15px;
+    line-height: 48px;
+}
+
+/*
+    MAST HEAD DROPDOWN MENU
+*/
+
+#mast-right div.ctrl-btns {
+    float: right;
+}
+
+#mast-right div.icon {
+    box-sizing: border-box;
+    position: relative;
+    height: 48px;
+    width: 48px;
+    padding: 9px;
+}
+
+#mast .dropdown-parent {
+    position: relative;
+    float: right;
+}
+
+#mast .dropdown-parent i.dropdown-icon {
+    display: inline-block;
+    height: 7px;
+    width: 9px;
+    margin-left: 10px;
+    background: url('/data/img/dropdown-icon.png') no-repeat;
+}
+
+#mast .dropdown {
+    position: absolute;
+    top: 40px;
+    right: -8px;
+    display: none;
+    min-width: 100px;
+    line-height: 16px;
+    font-size: 12pt;
+    z-index: 1000;
+}
+
+#mast .dropdown a {
+    text-decoration: none;
+    font-size: 12px;
+    display: block;
+    padding: 8px 16px 6px 12px;
+}
+
+#mast .dropdown-parent:hover .dropdown {
+    display: block;
+}
+
+#mast .dropdown-parent:hover i.dropdown-icon {
+    background-position-x: -14px
+}
+
+html[data-platform='iPad'] #mast .dropdown {
+    top: 57px;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.html b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.html
new file mode 100644
index 0000000..94d8ce0
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.html
@@ -0,0 +1,25 @@
+<div id="mast" align="left">
+    <span class="nav-menu-button clickable" (click)="ns.toggleNav()">
+        <img src="data/img/nav-menu-mojo.png"/>
+    </span>
+    <img class="logo" src="data/img/masthead-logo-mojo.png">
+    <div id="mast-right">
+        <nav>
+            <div class="dropdown-parent">
+                <a class="clickable user-menu__name">{{username}} <i class="dropdown-icon"></i></a>
+                <div class="dropdown">
+                    <!--<a href="rs/logout"> {{getLion('logout')}} </a> !!FIXME-->
+                    <a href="rs/logout">logout</a>
+                </div>
+            </div>
+            <div class="ctrl-btns">
+                <div class="active clickable icon"
+                     tooltip tt-msg="helpTip"
+                     ng-click="directTo()">
+                    <onos-icon iconId="query" iconSize="32"></onos-icon>
+                </div>
+            </div>
+        </nav>
+
+    </div>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.ts b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.ts
new file mode 100644
index 0000000..a8b85a4
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.component.ts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit } from '@angular/core';
+import { DialogService } from '../../layer/dialog.service';
+import { LionService } from '../../util/lion.service';
+import { LogService } from '../../../log.service';
+import { NavService } from '../../nav/nav.service';
+import { WebSocketService } from '../../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Masthead Component
+ */
+@Component({
+  selector: 'onos-mast',
+  templateUrl: './mast.component.html',
+  styleUrls: ['./mast.component.css', './mast.theme.css']
+})
+export class MastComponent implements OnInit {
+    public username;
+
+    constructor(
+        private ds: DialogService,
+        private ls: LionService,
+        private log: LogService,
+        public ns: NavService,
+        private wss: WebSocketService
+    ) {
+        this.log.debug('MastComponent constructed');
+
+    }
+
+    ngOnInit() {
+        // onosUser is a global set via the index.html generated source
+        // TODO: Fix onosuser below to get it from index.html like before
+        // TODO: Fix the lionService
+        this.username = 'onosUser'; // || this.getLion('unknown_user');
+
+        this.log.debug('MastComponent initialized');
+    }
+
+
+
+    /* In the case of Masthead, we cannot cache the lion bundle, because we
+     * call too early (before the lion data is uploaded from the server).
+     * So we'll dig into the lion service for each request...
+     */
+    getLion(x: string): string {
+      // lion is a function that takes a string and returns a string
+      const lion: (string) => string  = this.ls.bundle('core.fw.Mast');
+      return lion(x);
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/mast/mast/mast.theme.css b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.theme.css
new file mode 100644
index 0000000..6b92beb
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/mast/mast/mast.theme.css
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Masthead (theme) -- CSS file
+ */
+
+#mast {
+    background-color: #231f20;
+}
+
+#mast .nav-menu-button:hover {
+    background-color: #888;
+}
+
+#mast-right a {
+    color: #009fdb;
+}
+
+#mast nav  {
+    color: #009fdb;
+}
+
+/* Theme styles for drop down menu */
+
+#mast .dropdown {
+    background-color: #231f20;
+    border: 1px solid #dddddd;
+}
+
+#mast .dropdown a {
+    color: #009fdb;
+    border-bottom: solid #444 1px;
+}
+
+#mast .dropdown a:hover {
+    color: #fff;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav.module.ts b/web/gui2/src/main/webapp/app/fw/nav/nav.module.ts
new file mode 100644
index 0000000..95a3c31
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav.module.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule, Routes } from '@angular/router';
+import { SvgModule } from '../svg/svg.module';
+
+import { NavComponent } from './nav/nav.component';
+import { NavService } from './nav.service';
+
+import { AppsComponent } from '../../view/apps/apps.component';
+import { DeviceComponent } from '../../view/device/device.component';
+
+/**
+ * ONOS GUI -- Navigation Module
+ */
+@NgModule({
+  imports: [
+    CommonModule,
+    RouterModule,
+    SvgModule
+  ],
+  declarations: [
+    NavComponent
+  ],
+  exports: [
+    NavComponent
+  ],
+  providers: [
+    NavService
+  ]
+})
+export class NavModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav.service.ts b/web/gui2/src/main/webapp/app/fw/nav/nav.service.ts
new file mode 100644
index 0000000..22a903e
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav.service.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Navigation Service
+ */
+@Injectable()
+export class NavService {
+    public showNav = false;
+
+    constructor(
+        private _fn_: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('NavService constructed');
+    }
+
+    hideNav() {
+        this.showNav = !this.showNav;
+        if (!this.showNav) {
+            this.log.debug('Hiding Nav menu');
+        }
+    }
+
+    toggleNav() {
+        this.showNav = !this.showNav;
+        if (this.showNav) {
+            this.log.debug('Showing Nav menu');
+        } else {
+            this.log.debug('Hiding Nav menu');
+        }
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.css b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.css
new file mode 100644
index 0000000..3d2f646
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.css
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Navigation (layout) -- CSS file
+ */
+
+#nav {
+    position: absolute;
+    top: 48px;
+    left: 0;
+    padding: 0;
+    z-index: 3000;
+    visibility: hidden;
+}
+
+html[data-platform='iPad'] #nav {
+    top: 60px;
+}
+
+#nav .nav-hdr {
+    font-weight: bold;
+    font-variant: small-caps;
+    text-transform: uppercase;
+    font-size: 12pt;
+    padding: 8px 15px;
+}
+
+#nav a {
+    text-decoration: none;
+    font-size: 12pt;
+    font-weight: lighter;
+    display: block;
+    padding: 6px 10px;
+    margin: 0 7px;
+}
+
+#nav a div {
+    display: inline-block;
+    vertical-align: middle;
+    padding-right: 4px;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.html b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.html
new file mode 100644
index 0000000..a612214
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.html
@@ -0,0 +1,10 @@
+<nav id="nav" [@navState]="ns.showNav?'active':'inactive'">
+    <div class="nav-hdr">Platform</div>
+    <a (click)="ns.hideNav()" routerLink="/apps" routerLinkActive="active">
+        <!--<div onosIcon iconId="nav_apps"></div>
+         Using the new IconComponent rather than the directive -->
+        <onos-icon iconId="nav_apps"></onos-icon>Apps</a>
+    <div class="nav-hdr">Network</div>
+    <a (click)="ns.hideNav()" routerLink="/devices" routerLinkActive="active">
+        <onos-icon iconId="nav_devs"></onos-icon>Devices</a>
+</nav>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.ts b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.ts
new file mode 100644
index 0000000..27ae8de
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.component.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit } from '@angular/core';
+import { LogService } from '../../../log.service';
+import { NavService } from '../nav.service';
+import { trigger, state, style, animate, transition } from '@angular/animations';
+
+/**
+ * ONOS GUI -- Navigation Module
+ */
+@Component({
+  selector: 'onos-nav',
+  templateUrl: './nav.component.html',
+  styleUrls: ['./nav.theme.css', './nav.component.css'],
+  animations: [
+    trigger('navState', [
+      state('inactive', style({
+        visibility: 'hidden',
+        transform: 'translateX(-100%)'
+      })),
+      state('active', style({
+        visibility: 'visible',
+        transform: 'translateX(0%)'
+      })),
+      transition('inactive => active', animate('100ms ease-in')),
+      transition('active => inactive', animate('100ms ease-out'))
+    ])
+  ]
+})
+export class NavComponent implements OnInit {
+
+  constructor(
+    private log: LogService,
+    public ns: NavService
+  ) {
+    this.log.debug('NavComponent constructed');
+  }
+
+  ngOnInit() {
+    this.log.debug('NavComponent initialized');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/nav/nav/nav.theme.css b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.theme.css
new file mode 100644
index 0000000..1a308ac
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/nav/nav/nav.theme.css
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Navigation (theme) -- CSS file
+ */
+
+#nav {
+    background-color: #231f20;
+}
+
+#nav .nav-hdr {
+    color: #716b6a;
+    background-color: #3c3a3a;
+}
+
+#nav a {
+    color: #c7c7c0;
+    border-bottom: solid #3c3a3a 1px;
+}
+
+#nav a:hover {
+    color: #ffffff;
+}
+
+/* With component styles isolation in Angular 6 these no longer work */
+#nav a div svg.embeddedIcon g.icon .glyph {
+    fill: #007dc4;
+}
+
+#nav a:hover div svg.embeddedIcon g.icon .glyph {
+    fill: #20b2ff;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/remote/remote.module.ts b/web/gui2/src/main/webapp/app/fw/remote/remote.module.ts
new file mode 100644
index 0000000..179988d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/remote.module.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SvgModule } from '../svg/svg.module';
+import { UtilModule } from '../util/util.module';
+
+import { UrlFnService } from './urlfn.service';
+import { WebSocketService } from './websocket.service';
+import { WSock } from './wsock.service';
+import { RestService } from './rest.service';
+
+/**
+ * ONOS GUI -- Remote Communications Module
+ */
+@NgModule({
+  imports: [
+    CommonModule,
+    SvgModule,
+    UtilModule
+  ],
+  providers: [
+    RestService,
+    UrlFnService,
+    WebSocketService,
+    WSock
+  ]
+})
+export class RemoteModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/remote/rest.service.ts b/web/gui2/src/main/webapp/app/fw/remote/rest.service.ts
new file mode 100644
index 0000000..2d6bfa2
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/rest.service.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+import { UrlFnService } from './urlfn.service';
+
+/**
+ * ONOS GUI -- Remote Communications Module -- REST Service
+ */
+@Injectable()
+export class RestService {
+
+  constructor(
+    private fs: FnService,
+    private log: LogService,
+    private ufs: UrlFnService
+  ) {
+    this.log.debug('RestService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.ts b/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.ts
new file mode 100644
index 0000000..4685a65
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+const uiContext = '/onos/ui/';
+const rsSuffix = uiContext + 'rs/';
+const wsSuffix = uiContext + 'websock/';
+
+/**
+ * ONOS GUI -- Remote -- General Purpose URL Functions
+ */
+@Injectable()
+export class UrlFnService {
+    constructor(
+        private log: LogService,
+        private window: Window
+    ) {
+        this.log.debug('UrlFnService constructed');
+    }
+
+    matchSecure(protocol: string): string {
+        const p: string = window.location.protocol;
+        const secure: boolean = (p === 'https' || p === 'wss');
+        return secure ? protocol + 's' : protocol;
+    }
+
+    /* A little bit of funky here. It is possible that ONOS sits
+     * behind a proxy and has an app prefix, e.g.
+     *      http://host:port/my/app/onos/ui...
+     * This bit of regex grabs everything after the host:port and
+     * before the uiContext (/onos/ui/) and uses that as an app
+     * prefix by inserting it back into the WS URL.
+     * If no prefix, then no insert.
+     */
+    urlBase(protocol: string, port: string, host: string): string {
+        const match = window.location.href.match('.*//[^/]+/(.+)' + uiContext);
+        const appPrefix = match ? '/' + match[1] : '';
+
+        return this.matchSecure(protocol) + '://' +
+            (host || window.location.hostname) + ':' +
+            (port || window.location.port) + appPrefix;
+    }
+
+    httpPrefix(suffix: string): string {
+        return this.urlBase('http', '', '') + suffix;
+    }
+
+    wsPrefix(suffix: string, wsport: any, host: string): string {
+        return this.urlBase('ws', wsport, host) + suffix;
+    }
+
+    rsUrl(path: string): string {
+        return this.httpPrefix(rsSuffix) + path;
+    }
+
+    wsUrl(path: string, wsport: any, host: string): string {
+        return this.wsPrefix(wsSuffix, wsport, host) + path;
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
new file mode 100644
index 0000000..4189418
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { GlyphService } from '../svg/glyph.service';
+import { LogService } from '../../log.service';
+import { UrlFnService } from './urlfn.service';
+import { WSock } from './wsock.service';
+
+/**
+ * Event Type structure for the WebSocketService
+ */
+interface EventType {
+    event: string;
+    payload: any;
+}
+
+/**
+ * ONOS GUI -- Remote -- Web Socket Service
+ */
+@Injectable()
+export class WebSocketService {
+    // internal state
+    private webSockOpts; // web socket options
+    private ws = null; // web socket reference
+    private wsUp = false; // web socket is good to go
+    private handlers = {}; // event handler bindings
+    private pendingEvents: EventType[] = []; // events TX'd while socket not up
+    private host: string; // web socket host
+    private url; // web socket URL
+    private clusterNodes = []; // ONOS instances data for failover
+    private clusterIndex = -1; // the instance to which we are connected
+    private glyphs = [];
+    private connectRetries = 0; // limit our attempts at reconnecting
+    private openListeners = {}; // registered listeners for websocket open()
+    private nextListenerId = 1; // internal ID for open listeners
+    private loggedInUser = null; // name of logged-in user
+
+
+    constructor(
+        private fs: FnService,
+        private gs: GlyphService,
+        private log: LogService,
+        private ufs: UrlFnService,
+        private wsock: WSock,
+        private window: Window
+    ) {
+        this.log.debug(window.location.hostname);
+        this.log.debug('WebSocketService constructed');
+    }
+
+    /* ===================
+     * === API Functions
+     *
+     * Required for unit tests to set to known state
+     */
+    resetState() {
+        this.webSockOpts = undefined;
+        this.ws = null;
+        this.wsUp = false;
+        this.host = undefined;
+        this.url = undefined;
+        this.pendingEvents = [];
+        this.handlers = {};
+        this.clusterNodes = [];
+        this.clusterIndex = -1;
+        this.glyphs = [];
+        this.connectRetries = 0;
+        this.openListeners = {};
+        this.nextListenerId = 1;
+
+    }
+
+    /* Currently supported opts:
+     *  wsport: web socket port (other than default 8181)
+     *  host:   if defined, is the host address to use
+     */
+    createWebSocket(opts, _host_: string = '') {
+        let wsport = (opts && opts.wsport) || null;
+
+        this.webSockOpts = opts; // preserved for future calls
+
+//        this.host = _host_ || this.host();
+        let url = this.ufs.wsUrl('core', wsport, _host_);
+
+        this.log.debug('Attempting to open websocket to: ' + url);
+        this.ws = this.wsock.newWebSocket(url);
+        if (this.ws) {
+            this.ws.onopen = this.handleOpen();
+            this.ws.onmessage = this.handleMessage('???');
+            this.ws.onclose = this.handleClose();
+
+//            sendEvent('authentication', { token: onosAuth });
+            this.sendEvent('authentication token', '');
+        }
+        // Note: Wsock logs an error if the new WebSocket call fails
+        return url;
+    }
+
+    handleOpen() {
+        this.log.debug('WebSocketService: handleOpen() not yet implemented');
+    }
+
+    handleMessage(msgEvent: any) {
+        this.log.debug('WebSocketService: handleMessage() not yet implemented');
+    }
+
+    handleClose() {
+        this.log.debug('WebSocketService: handleClose() not yet implemented');
+    }
+
+    /* Formulates an event message and sends it via the web-socket.
+     * If the websocket is not up yet, we store it in a pending list.
+     */
+    sendEvent(evType, payload) {
+        let ev = <EventType> {
+            event: evType,
+            payload: payload
+        }
+
+        if (this.wsUp) {
+            this._send(ev);
+        } else {
+            this.pendingEvents.push(ev);
+        }
+    }
+
+    _send(ev: EventType) {
+        if (this.fs.debugOn('txrx')) {
+            this.log.debug(' *Tx* >> ', ev.event, ev.payload);
+        }
+        this.ws.send(JSON.stringify(ev));
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/remote/wsock.service.ts b/web/gui2/src/main/webapp/app/fw/remote/wsock.service.ts
new file mode 100644
index 0000000..176b5d3
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/wsock.service.ts
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Remote -- Web Socket Wrapper Service
+ *
+ * This service provided specifically so that it can be mocked in unit tests.
+ */
+@Injectable()
+export class WSock {
+
+  constructor(
+    private log: LogService,
+  ) {
+    this.log.debug('WSockService constructed');
+  }
+
+
+  newWebSocket(url) {
+      let ws = null;
+      try {
+          ws = new WebSocket(url);
+      } catch (e) {
+          this.log.error('Unable to create web socket:', e);
+      }
+      return ws;
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/geodata.service.ts b/web/gui2/src/main/webapp/app/fw/svg/geodata.service.ts
new file mode 100644
index 0000000..2594a1d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/geodata.service.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- SVG -- GeoData Service
+ *
+ * The GeoData Service facilitates the fetching and caching of TopoJSON data
+ * from the server, as well as providing a way of creating a path generator
+ * for that data, to be used to render the map in an SVG layer.
+ *
+ * A TopoData object can be fetched by ID. IDs that start with an asterisk
+ * identify maps bundled with the GUI. IDs that do not start with an
+ * asterisk are assumed to be URLs to externally provided data.
+ *
+ *   var topodata = GeoDataService.fetchTopoData('*continental-us');
+ *
+ * The path generator can then be created for that data-set:
+ *
+ *   var gen = GeoDataService.createPathGenerator(topodata, opts);
+ *
+ * opts is an optional argument that allows the override of default settings:
+ *   {
+ *       objectTag: 'states',
+ *       projection: d3.geo.mercator(),
+ *       logicalSize: 1000,
+ *       mapFillScale: .95
+ *   };
+ *
+ * The returned object (gen) comprises transformed data (TopoJSON -> GeoJSON),
+ * the D3 path generator function, and the settings used ...
+ *
+ *  {
+ *      geodata:  { ... },
+ *      pathgen:  function (...) { ... },
+ *      settings: { ... }
+ *  }
+ */
+@Injectable()
+export class GeoDataService {
+
+    constructor(
+        private fn: FnService,
+//        private http: HttpService,
+        private log: LogService
+    ) {
+        this.log.debug('GeoDataService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts b/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts
new file mode 100644
index 0000000..5b080ea
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../../fw/util/fn.service';
+import { LogService } from '../../log.service';
+import * as gds from './glyphdata.service';
+import * as d3 from 'd3';
+
+// constants
+const msgGS = 'GlyphService.';
+const rg = 'registerGlyphs(): ';
+const rgs = 'registerGlyphSet(): ';
+
+/**
+ * ONOS GUI -- SVG -- Glyph Service
+ */
+@Injectable()
+export class GlyphService {
+    // internal state
+    glyphs = d3.map();
+
+    constructor(
+        private fs: FnService,
+//        private gd: GlyphDataService,
+        private log: LogService
+    ) {
+        this.clear();
+        this.init();
+        this.log.debug('GlyphService constructed');
+    }
+
+    warn(msg: string): void {
+        this.log.warn(msgGS + msg);
+    }
+
+    addToMap(key, value, vbox, overwrite: boolean, dups) {
+        if (!overwrite && this.glyphs.get(key)) {
+            dups.push(key);
+        } else {
+            this.glyphs.set(key, { id: key, vb: vbox, d: value });
+        }
+    }
+
+    reportDups(dups: string[], which: string): boolean {
+        const ok: boolean = (dups.length === 0);
+        const msg = 'ID collision: ';
+
+        if (!ok) {
+            dups.forEach((id) => {
+                this.warn(which + msg + '"' + id + '"');
+            });
+        }
+        return ok;
+    }
+
+    reportMissVb(missing: string[], which: string): boolean {
+        const ok: boolean = (missing.length === 0);
+        const msg = 'Missing viewbox property: ';
+
+        if (!ok) {
+            missing.forEach((vbk) => {
+                this.warn(which + msg + '"' + vbk + '"');
+            });
+        }
+        return ok;
+    }
+
+    clear() {
+        // start with a fresh map
+        this.glyphs = d3.map();
+    }
+
+    init() {
+        this.log.info('Registering glyphs');
+        this.registerGlyphs(gds.logos);
+        this.registerGlyphSet(gds.glyphDataSet);
+        this.registerGlyphSet(gds.badgeDataSet);
+        this.registerGlyphs(gds.spriteData);
+        this.registerGlyphSet(gds.mojoDataSet);
+        this.registerGlyphs(gds.extraGlyphs);
+    }
+
+    registerGlyphs(data: Map<string, string>, overwrite: boolean = false): boolean {
+        const dups: string[] = [];
+        const missvb: string[] = [];
+        for (let [key, value] of data.entries()) {
+            const vbk = '_' + key;
+            const vb = data.get(vbk);
+
+            if (key[0] !== '_') {
+                if (!vb) {
+                    missvb.push(vbk);
+                    continue;
+                }
+                this.addToMap(key, value, vb, overwrite, dups);
+            }
+        }
+        return this.reportDups(dups, rg) && this.reportMissVb(missvb, rg);
+    }
+
+    registerGlyphSet(data: Map<string, string>, overwrite: boolean = false): boolean {
+        const dups: string[] = [];
+        const vb: string = data.get('_viewbox');
+
+        if (!vb) {
+            this.warn(rgs + 'no "_viewbox" property found');
+            return false;
+        }
+
+        for (let [key, value] of data.entries()) {
+//        angular.forEach(data, function (value, key) {
+            if (key[0] !== '_') {
+                this.addToMap(key, value, vb, overwrite, dups);
+            }
+        }
+        return this.reportDups(dups, rgs);
+    }
+
+    ids() {
+        return this.glyphs.keys();
+    }
+
+    glyph(id) {
+        return this.glyphs.get(id);
+    }
+
+    glyphDefined(id) {
+        return this.glyphs.has(id);
+    }
+
+
+    /**
+     * Load definitions of a glyph
+     *
+     * Note: defs should be a D3 selection of a single <defs> element
+     */
+    loadDefs(defs, glyphIds: string[], noClear: boolean) {
+        const list = this.fs.isA(glyphIds) || this.ids();
+
+        if (!noClear) {
+            // remove all existing content
+            defs.html(null);
+        }
+
+        // load up the requested glyphs
+        list.forEach((id) => {
+            const g = this.glyph(id);
+            if (g) {
+                if (noClear) {
+                    // quick exit if symbol is already present
+                    // TODO: check if this should be a continue or break instead
+                    if (defs.select('symbol#' + g.id).size() > 0) {
+                        return;
+                    }
+                }
+                defs.append('symbol')
+                      .attr('id', g.id)
+                      .attr('viewBox', g.vb)
+                      .append('path')
+                      .attr('d', g.d);
+            }
+        });
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/glyphdata.service.ts b/web/gui2/src/main/webapp/app/fw/svg/glyphdata.service.ts
new file mode 100644
index 0000000..6001807
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/glyphdata.service.ts
@@ -0,0 +1,1324 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+
+// --- ONOS logo glyph ------------------------------------
+
+export const logos = new Map<string, string>([
+    [ '_bird', '352 224 113 112'],
+    [ 'bird', 'M427.7,300.4 c-6.9,0.6-13.1,5-19.2,7.1c-18.1,6.2-33.9,' +
+    '9.1-56.5,4.7c24.6,17.2,36.6,13,63.7,0.1c-0.5,0.6-0.7,1.3-1.3,' +
+    '1.9c1.4-0.4,2.4-1.7,3.4-2.2c-0.4,0.7-0.9,1.5-1.4,1.9c2.2-0.6,' +
+    '3.7-2.3,5.9-3.9c-2.4,2.1-4.2,5-6,8c-1.5,2.5-3.1,4.8-5.1,6.9c-1,' +
+    '1-1.9,1.9-2.9,2.9c-1.4,1.3-2.9,2.5-5.1,2.9c1.7,0.1,3.6-0.3,6.5' +
+    '-1.9c-1.6,2.4-7.1,6.2-9.9,7.2c10.5-2.6,19.2-15.9,25.7-18c18.3' +
+    '-5.9,13.8-3.4,27-14.2c1.6-1.3,3-1,5.1-0.8c1.1,0.1,2.1,0.3,3.2,' +
+    '0.5c0.8,0.2,1.4,0.4,2.2,0.8l1.8,0.9c-1.9-4.5-2.3-4.1-5.9-6c-2.3' +
+    '-1.3-3.3-3.8-6.2-4.9c-7.1-2.6-11.9,11.7-11.7-5c0.1-8,4.2-14.4,' +
+    '6.4-22c1.1-3.8,2.3-7.6,2.4-11.5c0.1-2.3,0-4.7-0.4-7c-2-11.2-8.4' +
+    '-21.5-19.7-24.8c-1-0.3-1.1-0.3-0.9,0c9.6,17.1,7.2,38.3,3.1,54.2' +
+    'C429.9,285.5,426.7,293.2,427.7,300.4z'],
+    [ '_cord', '0 0 110 110'],
+    [ 'cord', 'M92.5,62.3l-33,33,2.5,2.5c4.1,4.1,7.4,3.6,11.2-.1L95.9,75' +
+    'l-4.5-4.5,4.7-4.7-3.6-3.6Z' +
+    'm2.6,7L98.4,66l3.3,3.3-3.3,3.3-3.3-3.3Z' +
+    'M94.5,60l4.9-4.9,4.9,4.9-4.9,4.9Z' +
+    'M36.2,36.1L18.6,53.8c-7.8,7.8-5.8,17.4-2.4,22l-2.2-2.2' +
+    'c-10.6-10.6-11.2-20,0-31.2L28.2,28.1L31.3,25l8,8-3.1,3.1Z' +
+    'M55.5,55.4l3.6-3.6L66.9,44l-8-8l-2.5,2.5-5.2,5.2l-3.6,3.6' +
+    'L33.2,61.6C22,72.7,22.5,82.2,33.2,92.8L35.4,95' +
+    'c-3.4-4.5-5.4-14.1,2.4-22L55.5,55.4Z' +
+    'M50.7,21.7l-8-8L35,21.2l8,8,7.6-7.6Z' +
+    'M62.8,9.6L55.4,17l-8-8,7.4-7.4,8,8Z' +
+    'm0.7,18.3-7.6,7.6-8-8,7.6-7.6,8,8Z' +
+    'm26.1-6.6-8.1,8.1-8-8,8.1-8.1,8,8Z' +
+    'M79.3,31.5l-7.4,7.4-8-8,7.4-7.4,8,8Z' +
+    'M45.7,45.6L54.3,37l-8-8-8.6,8.6L23.4,51.8' +
+    'C12.2,63,12.8,72.4,23.4,83l2.2,2.2c-3.4-4.5-5.4-14.1,2.4-22Z' +
+    'M34.9,80.7l20.6,20.5c2,2,4.6,4.1,7.9,3.2-2.9,2.9-8.9,1.7-11.9-1.3' +
+    'L35.1,86.8,35,86.6H34.9l-0.8-.8' +
+    'a15,15,0,0,1,.1-1.9,14.7,14.7,0,0,1,.7-3.2Z' +
+    'm-0.6,7.4a21.3,21.3,0,0,0,5.9,11.7l5.7,5.7' +
+    'c3,3,9,4.1,11.9,1.3-3.3.9-5.9-1.2-7.9-3.2L34.3,88.1Z' +
+    'm3.5-12.4a16.6,16.6,0,0,0-2.3,3.6L57,100.8' +
+    'c3,3,9,4.1,11.9,1.3-3.3.9-5.9-1.2-7.9-3.2Z'],
+]);
+
+
+// --- Core glyphs ------------------------------------
+
+// NOTE: when adding glyphs, please also update GlyphConstants class.
+const tableFrame = 'M6.3,5.3h8.5v14.2h-8.5z' +
+        'M95.3,5.3h8.5v14.2h-8.5z' +
+        'M18.5,5.3h15.6v14.2h-15.6z' +
+        'M37.9,5.3h15.6v14.2h-15.6z' +
+        'M57,5.3h15.6v14.2h-15.6z' +
+        'M76.1,5.3h15.6v14.2h-15.6z' +
+        'M6.3,23.9h97.5v80.75h-97.5z';
+
+const rSquare = '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-10z';
+
+const octagon = 'M10,35l25-25h40l25,25v40l-25,25h-40l-25-25z';
+
+const circle = 'M10,55A45,45,0,0,1,100,55A45,45,0,0,1,10,55';
+
+const arrowsLR = 'M58,26l12,0,0-8,18,13-18,13,0-8-12,0z' +
+        'M58,60l12,0,0-8,18,13-18,13,0-8-12,0z' +
+        'M52,40l-12,0,0-8-18,13,18,13,0-8,12,0z' +
+        'M52,74l-12,0,0-8-18,13,18,13,0-8,12,0z';
+
+const arrowsInHOutV = 'M20,50l12,0,0-8,18,13-18,13,0-8-12,0z' +
+        'M90,50l-12,0,0-8-18,13,18,13,0-8,12,0z' +
+        'M50,47l0-12-8,0,13-18,13,18-8,0,0,12z' +
+        'M50,63l0,12-8,0,13,18,13-18-8,0,0-12z';
+
+const laser = 'M47.2,68.4L31.1,84.5,25.6,79,41.7,62.9Z' +
+        'M76.3,30.6A3.4,3.4,0,0,0,72.9,34a3.3,3.3,0,0,0,.3,1.3L44.7,63.7' +
+        'l1.7,1.7L74.8,37a3.2,3.2,0,0,0,1.5.4A3.4,3.4,0,1,0,76.3,30.6Z' +
+        'm0.9-2.9V23.8a0.8,0.8,0,0,0-.8-0.8H76.1a0.8,0.8,0,0,0-.8.8v3.9' +
+        'a0.8,0.8,0,0,0,.8.8h0.3A0.8,0.8,0,0,0,77.2,27.7Z' +
+        'm3.5,3.2,3.6-3.6a0.9,0.9,0,0,0,0-1.2H84.3a0.9,0.9,0,0,0-1.2,0' +
+        'l-3.6,3.6a0.9,0.9,0,0,0,0,1.2h0.1A0.9,0.9,0,0,0,80.7,30.9Z' +
+        'm1.8,4h3.9a0.8,0.8,0,0,0,.8-0.8V33.7a0.8,0.8,0,0,0-.8-0.8H82.6' +
+        'a0.8,0.8,0,0,0-.8.8V34A0.8,0.8,0,0,0,82.6,34.8Z' +
+        'm-16.3.1h3.9a0.8,0.8,0,0,0,.8-0.8V33.8a0.8,0.8,0,0,0-.8-0.8' +
+        'H66.2a0.8,0.8,0,0,0-.8.8v0.3A0.8,0.8,0,0,0,66.2,34.9Z' +
+        'm6.8-5.2-3.8-3.8a0.9,0.9,0,0,0-1.3,0a0.9,0.9,0,0,0,0,1.3' +
+        'L71.8,31A0.9,0.9,0,0,0,73,31A0.9,0.9,0,0,0,73.1,29.7Z' +
+        'M84.8,40.9L80.9,37a0.9,0.9,0,0,0-1.3,0a0.9,0.9,0,0,0,0,1.3' +
+        'l3.9,3.9a0.9,0.9,0,0,0,1.3,0A0.9,0.9,0,0,0,84.8,40.9Z' +
+        'm-7.6,3.2V40.2a0.8,0.8,0,0,0-.8-0.8H76.2a0.8,0.8,0,0,0-.8.8' +
+        'v3.9a0.8,0.8,0,0,0,.8.8h0.3A0.8,0.8,0,0,0,77.3,44.1Z';
+
+const fiberStar = 'M89,60V57H70.6a15,15,0,0,1-3.2,7.6l13,12.9L82.8,75v7.5' +
+        'H75.2l2.2-2.2-12.8-13A14.9,14.9,0,0,1,57,70.6V89h3.1l-5.3,5.4' +
+        'L49.4,89H53V70.6a13.2,13.2,0,0,1-8-3.2l-13.1,13,2.3,2.3H26.5' +
+        'V75.1l2.3,2.3,13-12.8A15,15,0,0,1,38.7,57H21v3l-5.4-5.4L21,49.3' +
+        'V53H38.7a13.1,13.1,0,0,1,3.2-8l-13-13.1-2.2,2.1V26.4h7.5l-2.4,2.4' +
+        'L45,41.8a13.2,13.2,0,0,1,8-3.2V21H49.4l5.4-5.4L60.1,21H57V38.6' +
+        'a14.9,14.9,0,0,1,7.6,3.2l12.9-13-2.4-2.3h7.5v7.6l-2.3-2.3L67.4,45' +
+        'a13.1,13.1,0,0,1,3.2,8H89V49.3l5.4,5.3Z';
+
+export const glyphDataSet = new Map<string, string>([
+    ['_viewbox', '0 0 110 110'],
+
+    ['uiAttached', 'M91.9,16.7H18.1A5.3,5.3,0,0,0,12.8,22V68' +
+    'a5.3,5.3,0,0,0,5.3,5.3H91.9A5.3,5.3,0,0,0,97.2,68V22' +
+    'A5.3,5.3,0,0,0,91.9,16.7ZM91.6,65.2H18.4V22.3H91.6V65.2Z' +
+    'M71.5,87.5h3.8v5.9h-40.6v-5.9h3.8v-1.7h5.4v-9.7h22.3v9.7h5.3v1.7z'],
+
+    // Small dot
+    ['unknown', 'M35,40a5,5,0,0,1,5-5h30a5,5,0,0,1,5,5v30a5,5,0,0,1-5,5' +
+    'h-30a5,5,0,0,1-5-5z'],
+
+    // Question mark for unknown device types
+    ['query', 'M51.4,69.9c0-0.9,0-1.6,0-2.1c0-2.7,0.4-5.1,1.2-7.1' +
+    'c0.6-1.5,1.5-3,2.8-4.5c0.9-1.1,2.6-2.7,5.1-4.8c2.4-2.1,4-3.8,' +
+    '4.8-5.1 c0.7-1.3,1.1-2.6,1.1-4.1c0-2.7-1.1-5.1-3.2-7.1c-2.1-2' +
+    '-4.8-3.1-7.9-3.1c-3,0-5.5,0.9-7.5,2.8c-2,1.9-3.3,4.8-4,8.7l-7.2' +
+    '-0.8 c0.7-5.3,2.6-9.3,5.8-12.1c3.2-2.8,7.5-4.2,12.8-4.2c5.6,0,' +
+    '10.1,1.5,13.4,4.5c3.3,3,5,6.7,5,10.9c0,2.5-0.6,4.8-1.8,6.8 ' +
+    's-3.5,4.6-6.9,7.6c-2.3,2-3.8,3.5-4.5,4.4c-0.7,1-1.2,2-1.6,3.3' +
+    'c-0.3,1.2-0.5,3.2-0.6,6H51.4z M51,83.8v-7.9h8v7.9H51z'],
+
+
+    // --- ONOS cluster node ---
+    ['node', 'M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5' +
+    'v65a5,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'],
+
+
+    // --- DEVICES ---
+    // See Device.DeviceType enum for the following...
+
+    // NOTE: 'other' should map to 'unknown' (.) above
+
+    // deprecated glyphs -- using Mojo Designs below -- m_*
+    ['switch', rSquare + arrowsLR],
+
+    ['router', circle + arrowsInHOutV],
+
+    ['roadm', octagon + arrowsLR],
+
+    ['otn', rSquare + laser],
+
+    ['roadm_otn', octagon + laser],
+
+    ['fiber_switch', rSquare + fiberStar],
+
+    ['microwave', '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.2' +
+    'v3.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.9' +
+    'l0,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.7' +
+    'c2.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.3' +
+    'c0.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'],
+
+    // NOTE: 'unrecognized' should map to 'query' (?) above
+
+
+    // --- HOSTS ---
+
+    // default glyph for a host
+    ['endstation', 'M10,15a5,5,0,0,1,5-5h65a5,5,0,0,1,5,5v80a5,5,0,0,1' +
+    '-5,5h-65a5,5,0,0,1-5-5zM87.5,14l11,11a3,10,0,0,1,2,10v40a3,10,' +
+    '0,0,1,-2,10l-11,11zM17,19a2,2,0,0,1,2-2h56a2,2,0,0,1,2,2v26a2,' +
+    '2,0,0,1-2,2h-56a2,2,0,0,1-2-2zM20,20h54v10h-54zM20,33h54v10h' +
+    '-54zM42,70a5,5,0,0,1,10,0a5,5,0,0,1-10,0z'],
+
+    ['bgpSpeaker', 'M10,40a45,35,0,0,1,90,0Q100,77,55,100Q10,77,10,40z' +
+    'M50,29l12,0,0-8,18,13-18,13,0-8-12,0zM60,57l-12,0,0-8-18,13,' +
+    '18,13,0-8,12,0z'],
+
+
+    // --- Miscellaneous glyphs ---------------------------------
+
+    ['chain', 'M60.4,77.6c-4.9,5.2-9.6,11.3-15.3,16.3c-8.6,7.5-20.4,6.8' +
+    '-28-0.8c-7.7-7.7-8.4-19.6-0.8-28.4c6.5-7.4,13.5-14.4,20.9-20.9' +
+    'c7.5-6.7,19.2-6.7,26.5-0.8c3.5,2.8,4.4,6.1,2.2,8.7c-2.7,3.1' +
+    '-5.5,2.5-8.5,0.3c-4.7-3.4-9.7-3.2-14,0.9C37.1,58.7,31,64.8,' +
+    '25.2,71c-4.2,4.4-4.2,10.6-0.6,14.3c3.7,3.7,9.7,3.7,14.3-0.4' +
+    'c2.9-2.5,5.3-5.5,8.3-8c1-0.9,3-1.1,4.4-0.9C54.8,76.3,57.9,77.1,' +
+    '60.4,77.6zM49.2,32.2c5-5.2,9.7-10.9,15.2-15.7c12.8-11,31.2' +
+    '-4.9,34.3,11.2C100,34.2,98.3,40.2,94,45c-6.7,7.4-13.7,14.6' +
+    '-21.2,21.2C65.1,73,53.2,72.7,46,66.5c-3.2-2.8-3.9-5.8-1.6-8.4' +
+    'c2.6-2.9,5.3-2.4,8.2-0.3c5.2,3.7,10,3.3,14.7-1.1c5.8-5.6,11.6' +
+    '-11.3,17.2-17.2c4.6-4.8,4.9-11.1,0.9-15c-3.9-3.9-10.1-3.4-15,' +
+    '1.2c-3.1,2.9-5.7,7.4-9.3,8.5C57.6,35.3,53,33,49.2,32.2z'],
+
+    ['crown', 'M99.5,21.6c0,3-2.3,5.4-5.1,5.4c-0.3,0-0.7,0-1-0.1c-1.8,' +
+    '4-4.8,10-7.2,17.3c-3.4,10.6-0.9,26.2,2.7,27.3C90.4,72,91.3,' +
+    '75,88,75H22.7c-3.3,0-2.4-3-0.9-3.5c3.6-1.1,6.1-16.7,2.7-27.3' +
+    'c-2.4-7.4-5.4-13.5-7.2-17.5c-0.5,0.2-1,0.3-1.6,0.3c-2.8,0' +
+    '-5.1-2.4-5.1-5.4c0-3,2.3-5.4,5.1-5.4c2.8,0,5.1,2.4,5.1,5.4c0,' +
+    '1-0.2,1.9-0.7,2.7c0.7,0.8,1.4,1.6,2.4,2.6c8.8,8.9,11.9,12.7,' +
+    '18.1,11.7c6.5-1,11-8.2,13.3-14.1c-2-0.8-3.3-2.7-3.3-5.1c0-3,' +
+    '2.3-5.4,5.1-5.4c2.8,0,5.1,2.4,5.1,5.4c0,2.5-1.6,4.5-3.7,5.2' +
+    'c2.3,5.9,6.8,13,13.2,14c6.2,1,9.3-2.7,18.1-11.7c0.7-0.7,1.4' +
+    '-1.5,2-2.1c-0.6-0.9-1-2-1-3.1c0-3,2.3-5.4,5.1-5.4C97.2,16.2,' +
+    '99.5,18.6,99.5,21.6zM92,87.9c0,2.2-1.7,4.1-3.8,4.1H22.4c' +
+    '-2.1,0-4.4-1.9-4.4-4.1v-3.3c0-2.2,2.3-4.5,4.4-4.5h65.8c2.1,' +
+    '0,3.8,2.3,3.8,4.5V87.9z'],
+
+    ['lock', 'M79.4,48.6h-2.7c0.2-5.7-0.2-20.4-7.9-28.8c-3.6-3.9-8.3' +
+    '-5.9-13.7-5.9c-5.4,0-10.2,2-13.8,5.9c-7.8,8.4-8.3,23.2-8.1,28.8' +
+    'h-2.7c-4.4,0-8,2.6-8,5.9v35.7c0,3.3,3.6,5.9,8,5.9h48.9c4.4,0,' +
+    '8-2.6,8-5.9V54.5C87.5,51.3,83.9,48.6,79.4,48.6z M48.1,26.1c1.9' +
+    '-2,4.1-2.9,7-2.9c2.9,0,5.1,0.9,6.9,2.9c5,5.4,5.6,17.1,5.4,22.6' +
+    'h-25C42.3,43.1,43.1,31.5,48.1,26.1z'],
+
+    ['topo', 'M97.2,76.3H86.6l-7.7-21.9H82c1,0,1.9-0.8,1.9-1.9V35.7c' +
+    '0-1-0.8-1.9-1.9-1.9H65.2c-1,0-1.9,0.8-1.9,1.9v2.6L33.4,26.1v-11' +
+    'c0-1-0.8-1.9-1.9-1.9H14.7c-1,0-1.9,0.8-1.9,1.9v16.8c0,1,0.8,' +
+    '1.9,1.9,1.9h16.8c1,0,1.9-0.8,1.9-1.9v-2.6l29.9,12.2v9L30.5,76.9' +
+    'c-0.3-0.3-0.8-0.5-1.3-0.5H12.4c-1,0-1.9,0.8-1.9,1.9V95c0,1,0.8,' +
+    '1.9,1.9,1.9h16.8c1,0,1.9-0.8,1.9-1.9v-6.9h47.4V95c0,1,0.8,1.9,' +
+    '1.9,1.9h16.8c1,0,1.9-0.8,1.9-1.9V78.2C99.1,77.2,98.2,76.3,97.2,' +
+    '76.3z M31.1,85.1v-4.9l32.8-26.4c0.3,0.3,0.8,0.5,1.3,0.5h10.5l' +
+    '7.7,21.9h-3c-1,0-1.9,0.8-1.9,1.9v6.9H31.1z'],
+
+    ['refresh',
+   'M99.7,53.8l-10,13.3L85,73.5,78,64,70.4,53.7h9' +
+   'A28.5,28.5,0,1,0,68.3,77.6l10.6,6.9A40.7,40.7,0,1,1,91.6,53.8h8.2Z'],
+
+    ['garbage', 'M55.1,31.1c9.4,0,18.7.1,28.1-.1,3.2-.1,4.2,1,3.7,4.1' +
+    'q-4.1,28.6-8,57.3c-0.3,2.3-1.3,3.4-3.5,3.4h-41' +
+    'c-2.2,0-2.9-1.2-3.2-3.2Q27,63.5,22.7,34.4c-0.4-2.8.6-3.4,3.1-3.4' +
+    'H55.1Z' +
+    'M44.3,81.9c0.4-1.1-2.5-27.4-3.8-40.5a3.2,3.2,0,0,0-3.7-3.2' +
+    'c-2.5.1-2.5,1.9-2.4,3.7,0.5,4.9,1,9.8,1.5,14.7,0.8,8.1,1.6,16.2,' +
+    '2.4,24.2,0.2,2.2,1.1,4.1,3.6,3.4A3.6,3.6,0,0,0,44.3,81.9Z' +
+    'm21.2,0a2.8,2.8,0,0,0,2.2,2.3' +
+    'c2.3,0.8,3.7-.7,4-3.1,1.3-12.9,2.6-25.7,3.8-38.6,0.2-2,.3-4.1-2.6-4.4' +
+    's-3.3,1.7-3.5,3.7C68.1,54.8,65.5,81.1,65.5,81.9Z' +
+    'M57.9,61.3q0-9.8,0-19.6c0-2.2-.8-3.6-3.2-3.5s-2.6,1.7-2.6,3.6' +
+    'q0,19.4,0,38.8c0,1.9,0,3.8,2.8,3.9s3-1.8,3-3.9Q57.9,70.9,57.9,61.3Z' +
+    'M19,24.7c0.3-2,.5-5.7,1.5-8a5.1,5.1,0,0,1,3.6-2.3' +
+    'c5.5-.5,17.3-0.8,17.3-0.8l4.3-3.3H62.9l5.6,3.5S84.5,14.6,87,15' +
+    's2.5,0.7,3.2,1.9,0.9,7.4.9,7.4Z'],
+
+    ['cog', 'M100.2,46.4L87.1,44.8l-2.1-5L93.1,29a2.3,2.3,0,0,0-.2-3' +
+    'l-8.7-8.8a2.4,2.4,0,0,0-3.1-.2l-11,7.9L66,23.1,63.1,9.5' +
+    'A2.1,2.1,0,0,0,60.8,8H49.3A2.1,2.1,0,0,0,47,9.5L44.2,22.7l-5,2.2' +
+    'L28.8,16.8a2.3,2.3,0,0,0-3.1.2l-9.2,9.2a2.4,2.4,0,0,0-.2,3.2' +
+    'l8.1,10.4-1.7,4.1L9.8,46.4A2.3,2.3,0,0,0,8,48.7V61.9' +
+    'a2.3,2.3,0,0,0,2,2.4L22.6,66l1.7,5.2-7.7,10a2.4,2.4,0,0,0,.2,3.2' +
+    'l9.1,9a2.4,2.4,0,0,0,3.3.1l9-8.2,4.8,2.2,2.6,12.7' +
+    'a2.3,2.3,0,0,0,2.4,1.9l13.9-.2a2.5,2.5,0,0,0,2.3-2.4' +
+    'l0.7-11.4,5.5-2.3,9.8,8.1a2.4,2.4,0,0,0,3.2-.1L93,83.9' +
+    'a2.4,2.4,0,0,0,.1-3.3L84.7,71,87,66l13.2-2.5a2.3,2.3,0,0,0,1.9-2.3' +
+    'l0.2-12.5A2.4,2.4,0,0,0,100.2,46.4ZM54.4,73' +
+    'A18.2,18.2,0,1,1,72.6,54.8,18.2,18.2,0,0,1,54.4,73Z'],
+
+    ['delta', 'M55,19.2L13.7,90.8h82.7L55,19.2z ' +
+    'M55,31.2l30.9,53.5H24.1L55,31.2z'],
+
+    ['nonzero', 'M76.7,25.1l7.8-13.5l-7.6-0.3l-5.7,9.9' +
+    'c-4.8-2.9-10.4-4.5-16.2-4.5c-19.1,0-34.7,17.2-34.7,38.4' +
+    'c0,12.5,5.4,23.6,13.7,30.6l-7.6,13.2l7.6,0.1l5.5-9.6' +
+    'c4.7,2.6,9.9,4,15.5,4c19.1,0,34.7-17.2,34.7-38.4' +
+    'C89.7,42.9,84.6,32.1,76.7,25.1z M27.9,55C27.9,38.4,40,25,55,25' +
+    'c4.4,0,8.5,1.2,12.2,3.2l-29,50.3C31.9,73,27.9,64.5,27.9,55z' +
+    'M55,85c-4.1,0-7.9-1-11.4-2.8l29-50.1c5.8,5.5,9.5,13.7,9.5,22.8' +
+    'C82.1,71.6,70,85,55,85z'],
+
+    ['download', 'M90.3,94.5H19.7V79.2H90.3V94.5Z' +
+    'm-49.1-79V44H26.2L55,72.3,83.8,44H68.9V15.5H41.1Z'],
+
+    ['upload', 'M90.3,79.4H19.7V94.6H90.3V79.4Z' +
+    'M41.1,71.8V43.5H26.2L55,15.4,83.8,43.5H68.9V71.8H41.1Z'],
+
+    // --- Navigation glyphs ------------------------------------
+
+    ['flowTable', tableFrame +
+    'M86,63.2c0,3.3-2.7,6-6,6c-2.8,0-5.1-1.9-5.8-' +
+    '4.5H63.3v5.1c0,0.9-0.7,1.5-1.5,1.5h-5.2v10.6c2.6,0.7,4.5,3,4.5,' +
+    '5.8c0,3.3-2.7,6-6,6c-3.3,0-6-2.7-6-6c0-2.8,1.9-5.1,4.4-5.8V71.3' +
+    'H48c-0.9,0-1.5-0.7-1.5-1.5v-5.1H36c-0.7,2.6-3,4.4-5.8,4.4c-3.3,' +
+    '0-6-2.7-6-6s2.7-6,6-6c2.8,0,5.2,1.9,5.8,4.5h10.5V56c0-0.9,0.7-' +
+    '1.5,1.5-1.5h5.5V43.8c-2.6-0.7-4.5-3-4.5-5.8c0-3.3,2.7-6,6-6s6,' +
+    '2.7,6,6c0,2.8-1.9,5.1-4.5,5.8v10.6h5.2c0.9,0,1.5,0.7,1.5,1.5v' +
+    '5.6h10.8c0.7-2.6,3-4.5,5.8-4.5C83.3,57.1,86,59.8,86,63.2z ' +
+    'M55.1,42.3c2.3,0,4.3-1.9,4.3-4.3c0-2.3-1.9-4.3-4.3-4.3' +
+    's-4.3,1.9-4.3,4.3C50.8,40.4,52.7,42.3,55.1,42.3z ' +
+    'M34.4,63.1c0-2.3-1.9-4.3-4.3-4.3s-4.3,1.9-4.3,4.3' +
+    's1.9,4.3,4.3,4.3S34.4,65.5,34.4,63.1z ' +
+    'M55.1,83.5c-2.3,0-4.3,1.9-4.3,4.3s1.9,4.3,4.3,4.3' +
+    's4.3-1.9,4.3-4.3S57.5,83.5,55.1,83.5z' +
+    'M84.2,63.2c0-2.3-1.9-4.3-4.3-4.3s-4.3,' +
+    '1.9-4.3,4.3s1.9,4.3,4.3,4.3S84.2,65.5,84.2,63.2z'],
+
+    ['portTable', tableFrame +
+    'M85.5,37.7c0-0.7-0.4-1.3-0.9-1.3H26.2c-0.5,0-' +
+    '0.9,0.6-0.9,1.3v34.6c0,0.7,0.4,1.3,0.9,1.3h11v9.6c0,1.1,0.5,2,' +
+    '1.2,2h9.1c0,0.2,0,0.3,0,0.5v3c0,1.1,0.5,2,1.2,2h13.5c0.6,0,1.2-' +
+    '0.9,1.2-2v-3c0-0.2,0-0.3,0-0.5h9.1c0.6,0,1.2-0.9,1.2-2v-9.6h11' +
+    'c0.5,0,0.9-0.6,0.9-1.3V37.7z M30.2,40h-1v8h1V40zM75.2,40h-2.1v8' +
+    'h2.1V40z M67.7,40h-2.1v8h2.1V40z M60.2,40h-2.1v8h2.1V40z M52.7,' +
+    '40h-2.1v8h2.1V40z M45.2,40h-2.1v8h2.1V40zM37.7,40h-2.1v8h2.1V40' +
+    'z M81.6,40h-1v8h1V40z'],
+
+    ['groupTable', tableFrame +
+    'M45.7,52.7c0.2-5.6,2.6-10.7,6.2-14.4c-2.6-1.5-5.7-2.5-8.9-2.5' +
+    'c-9.8,0-17.7,7.9-17.7,17.7c0,6.3,3.3,11.9,8.3,15' +
+    'C34.8,61.5,39.4,55.6,45.7,52.7z ' +
+    'M51.9,68.8c-3.1-3.1-5.2-7.2-6-11.7c-4.7,2.8-7.9,7.6-8.6,13.2' +
+    'c1.8,0.6,3.6,0.9,5.6,0.9C46.2,71.2,49.3,70.3,51.9,68.8z ' +
+    'M55.2,71.5c-3.5,2.4-7.7,3.7-12.2,3.7c-1.9,0-3.8-0.3-5.6-0.7' +
+    'C38.5,83.2,45.9,90,54.9,90c9,0,16.4-6.7,17.5-15.4' +
+    'c-1.6,0.4-3.4,0.6-5.1,0.6C62.8,75.2,58.6,73.8,55.2,71.5z ' +
+    'M54.9,50.6c1.9,0,3.8,0.3,5.6,0.7c-0.5-4.1-2.5-7.9-5.4-10.6' +
+    'c-2.9,2.7-4.8,6.4-5.3,10.5C51.5,50.8,53.2,50.6,54.9,50.6z ' +
+    'M49.7,55.4c0.5,4.3,2.4,8.1,5.4,10.9c2.9-2.8,4.9-6.6,5.4-10.8' +
+    'c-1.8-0.6-3.6-0.9-5.6-0.9C53.1,54.6,51.4,54.9,49.7,55.4z ' +
+    'M89,53.5c0-12-9.7-21.7-21.7-21.7c-4.5,0-8.7,1.4-12.2,3.7' +
+    'c-3.5-2.4-7.7-3.7-12.2-3.7c-12,0-21.7,9.7-21.7,21.7' +
+    'c0,8.5,4.9,15.9,12,19.4C33.6,84.6,43.2,94,54.9,94' +
+    'c11.7,0,21.2-9.3,21.7-20.9C84,69.7,89,62.2,89,53.5z ' +
+    'M64.3,57.3c-0.8,4.4-2.9,8.4-5.9,11.5c2.6,1.5,5.7,2.5,8.9,2.5' +
+    'c1.8,0,3.6-0.3,5.2-0.8C72,64.9,68.8,60.1,64.3,57.3z ' +
+    'M67.3,35.8c-3.3,0-6.3,0.9-8.9,2.5c3.7,3.8,6.1,8.9,6.2,14.6' +
+    'c6.1,3.1,10.6,8.9,11.7,15.8C81.5,65.6,85,60,85,53.5' +
+    'C85,43.8,77.1,35.8,67.3,35.8z'],
+
+    ['meterTable', tableFrame +
+    'M96.3,79.2c0-19.1-22.1-34.6-41.3-34.6S13.7,60.1,13.7,79.2' +
+    'H39.4c0-7.2,8.4-13.1,15.7-13.1S70.6,72,70.6,79.2H96.3z' +
+    'M48,65.6L36.8,53c0-.5-1.5.5-1.4,0.7l5.3,16.6z'],
+
+    ['pipeconfTable', tableFrame +
+    'M10,66h13v3h-13z' +
+    'M23,62.5L28,67.5L23,72.5z' +
+    'M30,55h12.5v25h-12.5z' +
+    'M45,66h13v3h-13z' +
+    'M58,62.5L63,67.5L58,72.5z' +
+    'M65,55h12.5v25h-12.5z' +
+    'M79,66h15v3h-15z' +
+    'M94,62.5L99,67.5L94,72.5z'],
+
+    // --- Topology toolbar specific glyphs ----------------------
+
+    ['summary', 'M95.8,9.2H14.2c-2.8,0-5,2.2-5,5v81.5c0,2.8,2.2,5,5,' +
+    '5h81.5c2.8,0,5-2.2,5-5V14.2C100.8,11.5,98.5,9.2,95.8,9.2z ' +
+    'M16.7,22.2c0-1.1,0.9-2,2-2h20.1c1.1,0,2,0.9,2,2v20.1c0,1.1-0.9,' +
+    '2-2,2H18.7c-1.1,0-2-0.9-2-2V22.2z M93,87c0,1.1-0.9,2-2,2H18.9' +
+    'c-1.1,0-2-0.9-2-2v-7c0-1.1,0.9-2,2-2H91c1.1,0,2,0.9,2,2V87z ' +
+    'M93,65c0,1.1-0.9,2-2,2H18.9c-1.1,0-2-0.9-2-2v-7c0-1.1,0.9-2,' +
+    '2-2H91c1.1,0,2,0.9,2,2V65z'],
+
+    ['details', 'M95.8,9.2H14.2c-2.8,0-5,2.2-5,5v81.5c0,2.8,2.2,5,5,' +
+    '5h81.5c2.8,0,5-2.2,5-5V14.2C100.8,11.5,98.5,9.2,95.8,9.2z M16.9,' +
+    '22.2c0-1.1,0.9-2,2-2H91c1.1,0,2,0.9,2,2v7c0,1.1-0.9,2-2,2H18.9c' +
+    '-1.1,0-2-0.9-2-2V22.2z M93,87.8c0,1.1-0.9,2-2,2H18.9c-1.1,' +
+    '0-2-0.9-2-2v-7c0-1.1,0.9-2,2-2H91c1.1,0,2,0.9,2,2V87.8z M93,68.2' +
+    'c0,1.1-0.9,2-2,2H18.9c-1.1,0-2-0.9-2-2v-7c0-1.1,0.9-2,2-2H91' +
+    'c1.1,0,2,0.9,2,2V68.2z M93,48.8c0,1.1-0.9,2-2,2H19c-1.1,0-2-' +
+    '0.9-2-2v-7c0-1.1,0.9-2,2-2H91c1.1,0,2,0.9,2,2V48.8z'],
+
+    ['ports', 'M98,9.2H79.6c-1.1,0-2.1,0.9-2.1,2.1v17.6l-5.4,5.4c-1.7' +
+    '-1.1-3.8-1.8-6-1.8c-6,0-10.9,4.9-10.9,10.9c0,2.2,0.7,4.3,1.8,6' +
+    'l-7.5,7.5c-1.8-1.2-3.9-1.9-6.2-1.9c-6,0-10.9,4.9-10.9,10.9c0,' +
+    '2.3,0.7,4.4,1.9,6.2l-6.2,6.2H11.3c-1.1,0-2.1,0.9-2.1,2.1v18.4' +
+    'c0,1.1,0.9,2.1,2.1,2.1h18.4c1.1,0,2.1-0.9,2.1-2.1v-16l7-6.9' +
+    'c1.4,0.7,3,1.1,4.7,1.1c6,0,10.9-4.9,10.9-10.9c0-1.7-0.4-3.3-' +
+    '1.1-4.7l8-8c1.5,0.7,3.1,1.1,4.8,1.1c6,0,10.9-4.9,10.9-10.9c0' +
+    '-1.7-0.4-3.4-1.1-4.8l6.9-6.9H98c1.1,0,2.1-0.9,2.1-2.1V11.3' +
+    'C100.1,10.2,99.2,9.2,98,9.2z M43.4,72c-3.3,0-6-2.7-6-6s2.7-6,' +
+    '6-6s6,2.7,6,6S46.7,72,43.4,72z M66.1,49.5c-3.3,0-6-2.7-6-6' +
+    'c0-3.3,2.7-6,6-6s6,2.7,6,6C72.2,46.8,69.5,49.5,66.1,49.5z'],
+
+    ['map', 'M95.8,9.2H14.2c-2.8,0-5,2.2-5,5v66c0.3-1.4,0.7-2.8,' +
+    '1.1-4.1l1.6,0.5c-0.9,2.4-1.6,4.8-2.2,7.3l-0.5-0.1v12c0,2.8,2.2,' +
+    '5,5,5h81.5c2.8,0,5-2.2,5-5V14.2C100.8,11.5,98.5,9.2,95.8,9.2z ' +
+    'M16.5,67.5c-0.4,0.5-0.7,1-1,1.5c-0.3,0.5-0.6,1-0.9,1.6l-1.9-0.9' +
+    'c0.3-0.6,0.6-1.2,0.9-1.8c0.3-0.6,0.6-1.2,1-1.7c0.7-1.1,1.5-2.2,' +
+    '2.5-3.2l1.8,1.8C18,65.6,17.2,66.5,16.5,67.5z M29.7,64.1' +
+    'c-0.4-0.4-0.8-0.8-1.2-1.1c-0.1-0.1-0.2-0.1-0.2-0.1c0,0-0.1,' +
+    '0-0.1-0.1l-0.1,0l0,0l-0.1,0c-0.3-0.1-0.5-0.2-0.8-0.2c-0.5-0.1' +
+    '-1.1-0.2-1.6-0.3c-0.6,0-1.1,0-1.6,0l-0.4-2.8c0.7-0.1,1.5-0.2,2.2' +
+    '-0.1c0.7,0,1.4,0.1,2.2,0.3c0.4,0.1,0.7,0.2,1,0.3l0.1,0l0,0l0.1,' +
+    '0l0.1,0c0.1,0,0.1,0,0.3,0.1c0.3,0.1,0.5,0.2,0.7,0.4c0.7,0.5,' +
+    '1.2,0.9,1.7,1.4L29.7,64.1z M39.4,74.7c-1.8-1.8-3.6-3.8-5.3-5.7' +
+    'l2.6-2.4c0.9,0.9,1.8,1.8,2.7,2.7c0.9,0.9,1.8,1.7,2.7,2.6L39.4,' +
+    '74.7z M50.8,84.2c-1.1-0.7-2.2-1.5-3.3-2.3c-0.5-0.4-1.1-0.8-1.6' +
+    '-1.2c-0.5-0.4-1-0.8-1.5-1.2l2.7-3.4c0.5,0.4,1,0.8,1.5,1.1c0.5,' +
+    '0.3,1,0.7,1.5,1c1,0.7,2.1,1.3,3.1,1.9L50.8,84.2z M61.3,' +
+    '88.7c-0.7-0.1-1.4-0.3-2.1-0.5c-0.7-0.2-1.4-0.5-2-0.7l1.8' +
+    '-4.8c0.6,0.2,1.1,0.4,1.6,0.5c0.5,0.2,1.1,0.3,1.6,0.4c1,0.2,2.1,' +
+    '0.2,3,0.1l0.7,5.1C64.3,89.1,62.7,88.9,61.3,88.7z M75.1,80.4c' +
+    '-0.2,0.7-0.5,1.4-0.9,2c-0.2,0.3-0.3,0.7-0.5,1l-0.3,0.5l-0.3,' +
+    '0.4l-3.9-2.8l0.3-0.4l0.2-0.3c0.1-0.2,0.3-0.4,0.4-0.7c0.3-0.5,' +
+    '0.5-0.9,0.7-1.5c0.4-1,0.8-2.1,1.1-3.3l4.2,0.9C75.9,77.7,75.6,' +
+    '79,75.1,80.4z M73,69.2l0.2-1.9l0.1-1.9c0.1-1.2,0.1-2.5,0.1-' +
+    '3.8l2.5-0.2c0.2,1.3,0.4,2.6,0.5,3.9l0.1,2l0.1,2L73,69.2z ' +
+    'M73,51l0.5-0.1c0.4,1.3,0.8,2.6,1.1,3.9L73.2,55C73.1,53.7,73.1,' +
+    '52.3,73,51z M91.9,20.4c-0.7,1.4-3.6,3.6-4.2,3.9c-1.5,0.8-5,' +
+    '2.8-10.1,7.7c3,2.9,5.8,5.4,7.3,6.4c2.6,1.8,3.4,4.3,3.6,6.1c0.1,' +
+    '1.1-0.1,2.5-0.4,3c-0.5,0.9-1.6,2-3,1.4c-2-0.8-11.5-9.6-13-11c' +
+    '-3.5,3.9-7.4,8.9-11.7,15.1c0,0-3.1,3.4-5.2,0.9C52.9,51.5,61,' +
+    '39.3,61,39.3s2.2-3.1,5.6-7c-2.9-3-5.9-6.3-6.6-7.3c0,0-3.7-5-1.3' +
+    '-6.6c3.2-2.1,6.3,0.8,6.3,0.8s3.1,3.3,7,7.2c4.7-4.7,10.1-9.2,' +
+    '14.7-10c0,0,3.3-1,5.2,1.7C92.5,18.8,92.4,19.6,91.9,20.4z'],
+
+    ['cycleLabels', 'M72.5,33.9c0,0.6-0.2,1-0.5,1H40c-0.3,0-0.5-0.4' +
+    '-0.5-1V20.7c0-0.6,0.2-1,0.5-1h32c0.3,0,0.5,0.4,0.5,1V33.9z ' +
+    'M41.2,61.8c0-0.6-0.2-1-0.5-1h-32c-0.3,0-0.5,0.4-0.5,1V75c0,0.6,' +
+    '0.2,1,0.5,1h32c0.3,0,0.5-0.4,0.5-1V61.8z M101.8,61.8c0-0.6-0.2' +
+    '-1-0.5-1h-32c-0.3,0-0.5,0.4-0.5,1V75c0,0.6,0.2,1,0.5,1h32c0.3,' +
+    '0,0.5-0.4,0.5-1V61.8z M17.2,52.9c0-0.1-0.3-7.1,4.6-13.6l-2.4-1.8' +
+    'c-5.4,7.3-5.2,15.2-5.1,15.5L17.2,52.9z M12.7,36.8l7.4,2.5l1.5,' +
+    '7.6L29.5,31L12.7,36.8z M94.2,42.3c-2.1-8.9-8.3-13.7-8.6-13.9l' +
+    '-1.8,2.4c0.1,0,5.6,4.3,7.5,12.2L94.2,42.3z M99,37.8l-6.6,4.1l' +
+    '-6.8-3.7l7.1,16.2L99,37.8z M69,90.2l-1.2-2.8c-0.1,0-6.6,2.8' +
+    '-14.3,0.6l-0.8,2.9c2.5,0.7,4.9,1,7,1C65,91.8,68.7,90.2,69,90.2z ' +
+    'M54.3,97.3L54,89.5l6.6-4.1l-17.6-1.7L54.3,97.3z'],
+
+    ['oblique', 'M80.9,30.2h4.3l15-16.9H24.8l-15,16.9h19v48.5h-4l-15,' +
+    '16.9h75.3l15-16.9H80.9V30.2z M78.6,78.7H56.1V30.2h22.5V78.7z' +
+    'M79.7,17.4c2.4,0,4.3,1.9,4.3,4.3c0,2.4-1.9,4.3-4.3,4.3s-4.3' +
+    '-1.9-4.3-4.3C75.4,19.3,77.4,17.4,79.7,17.4z M55,17.4c2.4,0,' +
+    '4.3,1.9,4.3,4.3c0,2.4-1.9,4.3-4.3,4.3s-4.3-1.9-4.3-4.3C50.7,' +
+    '19.3,52.6,17.4,55,17.4z M26.1,21.7c0-2.4,1.9-4.3,4.3-4.3c2.4,' +
+    '0,4.3,1.9,4.3,4.3c0,2.4-1.9,4.3-4.3,4.3C28,26,26.1,24.1,26.1,' +
+    '21.7z M31.1,30.2h22.6v48.5H31.1V30.2z M30.3,91.4c-2.4,0-4.3' +
+    '-1.9-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3c2.4,0,4.3,1.9,4.3,4.3C34.6,' +
+    '89.5,32.7,91.4,30.3,91.4z M54.9,91.4c-2.4,0-4.3-1.9-4.3-4.3c0' +
+    '-2.4,1.9-4.3,4.3-4.3c2.4,0,4.3,1.9,4.3,4.3C59.2,89.5,57.3,' +
+    '91.4,54.9,91.4z M84,87.1c0,2.4-1.9,4.3-4.3,4.3c-2.4,0-4.3-1.9' +
+    '-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3C82.1,82.8,84,84.7,84,87.1z'],
+
+    ['filters', 'M24.8,13.3L9.8,40.5h75.3l15.0-27.2H24.8z M72.8,32.1l-' +
+    '9.7-8.9l-19.3,8.9l-6.0-7.4L24.1,30.9l-1.2-2.7l15.7-7.1l6.0,7.4' +
+    'l19.0-8.8l9.7,8.8l11.5-5.6l1.3,2.7L72.8,32.1zM24.3,68.3L9.3,' +
+    '95.5h75.3l15.0-27.2H24.3z M84.3,85.9L70.7,79.8l-6.0,7.4l-19.3' +
+    '-8.9l-9.7,8.9l-13.3-6.5l1.3-2.7l11.5,5.6l9.7-8.8l19.0,8.8l6.0' +
+    '-7.4l15.7,7.1L84.3,85.9z M15.3,57h-6v-4h6V57zM88.1,57H76.0v-4h' +
+    '12.1V57z M69.9,57H57.8v-4h12.1V57z M51.7,57H39.6v-4H51.7V57z ' +
+    'M33.5,57H21.4v-4h12.1V57zM100.2,57h-6v-4h6V57z'],
+
+    ['resetZoom', 'M86,79.8L61.7,54.3c1.8-2.9,2.8-6.3,2.9-10c0.3-11.2' +
+    '-8.6-20.5-19.8-20.8C33.7,23.2,24.3,32,24.1,43.2c-0.3,11.2,8.6,' +
+    '20.5,19.8,20.8c4,0.1,8.9-0.8,11.9-3.6l23.7,25c1.5,1.6,4,2.3,' +
+    '5.3,1l1.6-1.6C87.7,83.7,87.5,81.4,86,79.8z M31.4,43.4c0.2-7.1,' +
+    '6.1-12.8,13.2-12.6C51.8,31,57.5,37,57.3,44.1c-0.2,7.1-6.1,12.8' +
+    '-13.2,12.6C36.9,56.5,31.3,50.6,31.4,43.4zM22.6,104H6V86.4c0' +
+    '-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1v11.4h10.4c1.7,0,3.1,1.4,' +
+    '3.1,3.1S24.3,104,22.6,104z M25.7,9.1c0,1.7-1.4,3.1-3.1,3.1' +
+    'H12.2v11.4c0,1.7-1.4,3.1-3.1,3.1S6,25.3,6,23.6V6h16.6C24.3,6,' +
+    '25.7,7.4,25.7,9.1z M84.3,100.9c0-1.7,1.4-3.1,3.1-3.1h10.4V86.4' +
+    'c0-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1V104H87.4C85.7,104,84.3,' +
+    '102.6,84.3,100.9z M87.4,6H104v17.6c0,1.7-1.4,3.1-3.1,3.1s-3.1' +
+    '-1.4-3.1-3.1V12.2H87.4c-1.7,0-3.1-1.4-3.1-3.1S85.7,6,87.4,6z'],
+
+    ['relatedIntents', 'M99.9,43.7v22.6c0,1.9-1.5,3.4-3.4,3.4H73.9c' +
+    '-1.9,0-3.4-1.5-3.4-3.4V43.7c0-1.9,1.5-3.4,3.4-3.4h22.6C98.4,' +
+    '40.3,99.9,41.8,99.9,43.7z M48.4,46.3l6.2,6.7h-4.6L38.5,38v9.7' +
+    'l4.7,5.3H10.1V57h33.2l-4.8,5.3v9.5L49.8,57h5.1v0l-6.5,7v11.5' +
+    'L64.1,55L48.4,34.4V46.3z'],
+
+    ['nextIntent', 'M88.1,55.7L34.6,13.1c0,0-1.6-0.5-2.1-0.2c-1.9,1.2' +
+    '-6.5,13.8-3.1,17.2c7,6.9,30.6,24.5,32.4,25.9c-1.8,1.4-25.4,19' +
+    '-32.4,25.9c-3.4,3.4,1.2,16,3.1,17.2c0.6,0.4,2.1-0.2,2.1-0.2' +
+    's53.1-42.4,53.5-42.7C88.5,56,88.1,55.7,88.1,55.7z'],
+
+    ['prevIntent', 'M22.5,55.6L76,12.9c0,0,1.6-0.5,2.2-0.2c1.9,1.2,' +
+    '6.5,13.8,3.1,17.2c-7,6.9-30.6,24.5-32.4,25.9c1.8,1.4,25.4,19,' +
+    '32.4,25.9c3.4,3.4-1.2,16-3.1,17.2c-0.6,0.4-2.2-0.2-2.2-0.2' +
+    'S22.9,56.3,22.5,56C22.2,55.8,22.5,55.6,22.5,55.6z'],
+
+    ['intentTraffic', 'M14.7,71.5h-6v-33h6V71.5z M88.5,38.5H76.9v33' +
+    'h11.7V38.5z M70.1,38.5H58.4v33h11.7V38.5z M51.6,38.5H39.9v33' +
+    'h11.7V38.5z M33.1,38.5H21.5v33h11.7V38.5z M101.3,38.5h-6v33h6' +
+    'V38.5z'],
+
+    ['allTraffic', 'M15.7,64.5h-7v-19h7V64.5z M78.6,45.5H62.9v19h15.7' +
+    'V45.5z M47.1,45.5H31.4v19h15.7V45.5z M101.3,45.5h-7v19h7V45.5z' +
+    'M14.7,14.1h-6v19h6V14.1z M88.5,14.1H76.9v19h11.7V14.1z M70.1,' +
+    '14.1H58.4v19h11.7V14.1z M51.6,14.1H39.9v19h11.7V14.1z M33.1,14.1' +
+    'H21.5v19h11.7V14.1z M101.3,14.1h-6v19h6V14.1z M14.7,76.9h-6v19' +
+    'h6V76.9z M88.5,76.9H76.9v19h11.7V76.9z M70.1,76.9H58.4v19h11.7' +
+    'V76.9z M51.6,76.9H39.9v19h11.7V76.9z M33.1,76.9H21.5v19h11.7' +
+    'V76.9z M101.3,76.9h-6v19h6V76.9z'],
+
+    ['flows', 'M93.8,46.1c-4.3,0-8,3-9,7H67.9v-8.8c0-1.3-1.1-2.4-2.4' +
+    '-2.4h-8.1V25.3c4-1,7-4.7,7-9.1c0-5.2-4.2-9.4-9.4-9.4c-5.2,0' +
+    '-9.4,4.2-9.4,9.4c0,4.3,3,8,7,9v16.5H44c-1.3,0-2.4,1.1-2.4,2.4' +
+    'v8.8H25.3c-1-4.1-4.7-7.1-9.1-7.1c-5.2,0-9.4,4.2-9.4,9.4s4.2,' +
+    '9.4,9.4,9.4c4.3,0,8-2.9,9-6.9h16.4v7.9c0,1.3,1.1,2.4,2.4,2.4' +
+    'h8.6v16.6c-4,1.1-6.9,4.7-6.9,9c0,5.2,4.2,9.4,9.4,9.4c5.2,0,' +
+    '9.4-4.2,9.4-9.4c0-4.4-3-8-7.1-9.1V68.2h8.1c1.3,0,2.4-1.1,2.4' +
+    '-2.4v-7.9h16.8c1.1,4,4.7,7,9,7c5.2,0,9.4-4.2,9.4-9.4S99,46.1,' +
+    '93.8,46.1z M48.7,16.3c0-3.5,2.9-6.4,6.4-6.4c3.5,0,6.4,2.9,6.4,' +
+    '6.4s-2.9,6.4-6.4,6.4C51.5,22.6,48.7,19.8,48.7,16.3zM16.2,61.7c' +
+    '-3.5,0-6.4-2.9-6.4-6.4c0-3.5,2.9-6.4,6.4-6.4s6.4,2.9,6.4,6.4' +
+    'C22.6,58.9,19.7,61.7,16.2,61.7z M61.4,93.7c0,3.5-2.9,6.4-6.4,' +
+    '6.4c-3.5,0-6.4-2.9-6.4-6.4c0-3.5,2.9-6.4,6.4-6.4C58.6,87.4,' +
+    '61.4,90.2,61.4,93.7z M93.8,61.8c-3.5,0-6.4-2.9-6.4-6.4c0-3.5,' +
+    '2.9-6.4,6.4-6.4s6.4,2.9,6.4,6.4C100.1,58.9,97.3,61.8,93.8,61.8z'],
+
+    ['eqMaster', 'M100.1,46.9l-10.8-25h0.2c0.5,0,0.8-0.5,0.8-1.1v-3.2' +
+    'c0-0.6-0.4-1.1-0.8-1.1H59.2v-5.1c0-0.5-0.8-1-1.7-1h-5.1c-0.9,0' +
+    '-1.7,0.4-1.7,1v5.1l-30.2,0c-0.5,0-0.8,0.5-0.8,1.1v3.2c0,0.6,' +
+    '0.4,1.1,0.8,1.1h0.1l-10.8,25C9,47.3,8.4,48,8.4,48.8v1.6l0,0h0' +
+    'v6.4c0,1.3,1.4,2.3,3.2,2.3h21.7c1.8,0,3.2-1,3.2-2.3v-8c0-0.9' +
+    '-0.7-1.6-1.7-2L22.9,21.9h27.9v59.6l-29,15.9c0,1.2,1.8,2.2,4.1,' +
+    '2.2h58.3c2.3,0,4.1-1,4.1-2.2l-29-15.9V21.9h27.8L75.2,46.8c-1,' +
+    '0.4-1.7,1.1-1.7,2v8c0,1.3,1.4,2.3,3.2,2.3h21.7c1.8,0,3.2-1,3.2' +
+    '-2.3v-8C101.6,48,101,47.3,100.1,46.9z M22,23.7l10.8,22.8H12.1' +
+    'L22,23.7z M97.9,46.5H77.2L88,23.7L97.9,46.5z'],
+
+    ['xClose', 'M20,8l35,35,35-35,12,12-35,35,35,35-12,12-35-35-35,35' +
+    '-12-12,35-35-35-35,12-12Z'],
+]);
+
+export const badgeDataSet = new Map<string, string>([
+    ['_viewbox', '0 0 10 10'],
+
+    ['checkMark', 'M8.6,3.4L4.4,7.7L1.4,4.7L2.5,3.6L4.4,5.5L7.5,2.3L8.6,3.4Z'],
+
+    ['xMark', 'M7.8,6.7L6.7,7.8,5,6.1,3.3,7.8,2.2,6.7,3.9,5,2.2,3.3,3.3,' +
+    '2.2,5,3.9,6.7,2.2,7.8,3.3,6.1,5Z'],
+
+    ['triangleUp', 'M0.5,6.2c0,0,3.8-3.8,4.2-4.2C5,1.7,5.3,2,5.3,2l4.3,' +
+    '4.3c0,0,0.4,0.4-0.1,0.4c-1.7,0-8.2,0-8.8,0C0,6.6,0.5,6.2,0.5,6.2z'],
+
+    ['triangleDown', 'M9.5,4.2c0,0-3.8,3.8-4.2,4.2c-0.3,0.3-0.5,0-0.5,' +
+    '0L0.5,4.2c0,0-0.4-0.4,0.1-0.4c1.7,0,8.2,0,8.8,0C10,3.8,9.5,4.2,' +
+    '9.5,4.2z'],
+
+    ['plus', 'M4,2h2v2h2v2h-2v2h-2v-2h-2v-2h2z'],
+
+    ['minus', 'M2,4h6v2h-6z'],
+
+    ['play', 'M3,1.5l3.5,3.5l-3.5,3.5z'],
+
+    ['stop', 'M2.5,2.5h5v5h-5z'],
+]);
+
+export const spriteData = new Map<string, string>([
+    ['_cloud', '0 0 110 110'],
+    ['cloud', 'M37.6,79.5c-6.9,8.7-20.4,8.6-22.2-2.7' +
+    'M16.3,41.2c-0.8-13.9,19.4-19.2,23.5-7.8' +
+    'M38.9,30.9c5.1-9.4,15.1-8.5,16.9-1.3' +
+    'M54.4,32.9c4-12.9,14.8-9.6,18.6-3.8' +
+    'M95.8,58.5c10-4.1,11.7-17.8-0.9-19.8' +
+    'M18.1,76.4C5.6,80.3,3.8,66,13.8,61.5' +
+    'M16.2,62.4C2.1,58.4,3.5,36,16.8,36.6' +
+    'M93.6,74.7c10.2-2,10.7-14,5.8-18.3' +
+    'M71.1,79.3c11.2,7.6,24.6,6.4,22.1-11.7' +
+    'M36.4,76.8c3.4,13.3,35.4,11.6,36.1-1.4' +
+    'M70.4,31c11.8-10.4,26.2-5.2,24.7,10.1'],
+]);
+
+
+    // --- Mojo Re-Design ---------------------------------------
+const m_octagon = 'M33.5,91.9a1.8,1.8,0,0,1-1.3-.5L8.7,68a1.8,1.8,0,0,' +
+    '1-.5-1.3V33.5a1.8,1.8,0,0,1,.5-1.3L32,8.7a1.8,1.8,0,0,1,1.3-.5' +
+    'H66.5a1.8,1.8,0,0,1,1.3.5L91.3,32a1.8,1.8,0,0,1,.5,1.3V66.5' +
+    'a1.8,1.8,0,0,1-.5,1.3L68,91.3a1.8,1.8,0,0,1-1.3.5H33.5Z' +
+    'm-21.7-26L34.3,88.2H65.9L88.2,65.7V34.1L65.7,11.8H34.1' +
+    'L11.8,34.3V65.9Z';
+
+const m_switch_arrows = 'M60,42.1l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V33.8' +
+    'a1.8,1.8,0,0,1,3.7,0v3.3l13-7.1L61.9,23v3.3' +
+    'A1.8,1.8,0,0,1,60,28.2h-7v3.7h1.7a1.8,1.8,0,0,1,0,3.7H51.2' +
+    'a1.8,1.8,0,0,1-1.8-1.8V26.4a1.8,1.8,0,0,1,1.8-1.8h7V20' +
+    'a1.8,1.8,0,0,1,2.7-1.6l18.7,10a1.8,1.8,0,0,1,0,3.2L60.9,41.8Z' +
+    'M60,69.2l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V60.9a1.8,1.8,0,0,1,3.7,0' +
+    'v3.3l13-7.1-13-6.9v3.3A1.8,1.8,0,0,1,60,55.3h-7V59h1.7' +
+    'a1.8,1.8,0,0,1,0,3.7H51.2a1.8,1.8,0,0,1-1.8-1.8V53.5' +
+    'a1.8,1.8,0,0,1,1.8-1.8h7V47.1a1.8,1.8,0,0,1,2.7-1.6l18.7,10' +
+    'a1.8,1.8,0,0,1,0,3.2L60.9,69ZM40,54.8l-0.9-.2L20.4,44.2' +
+    'a1.8,1.8,0,0,1,0-3.2L39.1,31a1.8,1.8,0,0,1,2.7,1.6v4.5h7' +
+    'A1.8,1.8,0,0,1,50.6,39v7.4a1.8,1.8,0,0,1-1.8,1.8H45.2' +
+    'a1.8,1.8,0,0,1,0-3.7h1.7V40.9H40A1.8,1.8,0,0,1,38.1,39' +
+    'V35.7l-13,6.9,13,7.1V46.4a1.8,1.8,0,0,1,3.7,0v6.5' +
+    'a1.8,1.8,0,0,1-.9,1.6ZM40,81.9l-0.9-.2L20.4,71.4' +
+    'a1.8,1.8,0,0,1,0-3.2l18.7-10a1.8,1.8,0,0,1,2.7,1.6v4.5h7' +
+    'a1.8,1.8,0,0,1,1.8,1.8v7.4a1.8,1.8,0,0,1-1.8,1.8H45.2' +
+    'a1.8,1.8,0,0,1,0-3.7h1.7V68H40a1.8,1.8,0,0,1-1.8-1.8V62.9' +
+    'l-13,6.9,13,7.1V73.6a1.8,1.8,0,0,1,3.7,0V80a1.8,1.8,0,0,1-.9,1.6Z';
+
+const m_diamond = 'M50,87a16.1,16.1,0,0,1-11.5-4.7L17.7,61.5a16.3,16.3,0,0,' +
+    '1,0-22.9L38.5,17.7a16.3,16.3,0,0,1,22.9,0L82.3,38.5' +
+    'a16.3,16.3,0,0,1,0,22.9L61.5,82.3A16.1,16.1,0,0,1,50,87Z' +
+    'm0-70.3a12.4,12.4,0,0,0-8.9,3.7L20.3,41.1a12.6,12.6,0,0,0,0,' +
+    '17.7L41.1,79.7a12.6,12.6,0,0,0,17.7,0L79.7,58.9a12.6,12.6,0,0,' +
+    '0,0-17.7L58.9,20.3A12.4,12.4,0,0,0,50,16.7Z';
+
+const m_trafficArrows = 'M41,66.7l-0.9-.2-16.8-9a1.8,1.8,0,0,1,0-3.2' +
+    'L40.1,45a1.8,1.8,0,0,1,2.7,1.6v5.8a1.8,1.8,0,0,1-3.7,0V49.7' +
+    'L28,55.8l11.1,5.9V59.1A1.8,1.8,0,0,1,41,57.2H47v-3H45.7' +
+    'a1.8,1.8,0,0,1,0-3.7h3.2a1.8,1.8,0,0,1,1.8,1.8v6.7' +
+    'a1.8,1.8,0,0,1-1.8,1.8H42.8v3.9a1.8,1.8,0,0,1-.9,1.6ZM59,55.3' +
+    'l-1-.3a1.8,1.8,0,0,1-.9-1.6V49.5H51.1a1.8,1.8,0,0,1-1.8-1.8' +
+    'V41a1.8,1.8,0,0,1,1.8-1.8h3.2a1.8,1.8,0,0,1,0,3.7H53v3H59' +
+    'a1.8,1.8,0,0,1,1.8,1.8v2.7L72,44.4,60.9,38.3V41' +
+    'a1.8,1.8,0,0,1-3.7,0V35.2a1.8,1.8,0,0,1,2.7-1.6l16.8,9.3' +
+    'a1.8,1.8,0,0,1,0,3.2L59.9,55Z';
+
+const m_otn_base = 'M63.1,79.8a7.5,7.5,0,0,1-5.3-12.8,7.7,7.7,0,0,1,10.7,0' +
+    'A7.5,7.5,0,0,1,63.1,79.8Zm0-11.3A3.8,3.8,0,0,0,60.4,75h0' +
+    'a3.9,3.9,0,0,0,5.4,0A3.8,3.8,0,0,0,63.1,68.4Z' +
+    'M63.1,35.2A7.5,7.5,0,1,1,68.5,33h0A7.5,7.5,0,0,1,63.1,35.2Z' +
+    'm4-3.5h0Zm-4-7.8A3.8,3.8,0,1,0,65.8,25,3.8,3.8,0,0,0,63.1,23.9Z' +
+    'M73.3,57.3a7.5,7.5,0,1,1,7.5-7.5A7.5,7.5,0,0,1,73.3,57.3Z' +
+    'm0-11.3a3.8,3.8,0,1,0,3.8,3.8A3.8,3.8,0,0,0,73.3,46Z' +
+    'M61.9,48.7H51.5V41.9l5-5a1.9,1.9,0,0,0-2.6-2.6l-4.2,4.2L38,48.7' +
+    'H34.1A7.3,7.3,0,0,0,32,45a7.6,7.6,0,0,0-10.7,0,7.5,7.5,0,0,0,0,' +
+    '10.6,7.6,7.6,0,0,0,10.7,0,7.4,7.4,0,0,0,1.9-3.2h5.2' +
+    'l11.4,9.9,3.4,3.4a1.8,1.8,0,0,0,2.6,0,1.8,1.8,0,0,0,0-2.6l-5-5' +
+    'V52.4H61.9A1.9,1.9,0,0,0,61.9,48.7ZM29.4,53a3.8,3.8,0,0,1-6.5-2.7' +
+    'A3.9,3.9,0,0,1,24,47.6a3.9,3.9,0,0,1,5.4,0A3.8,3.8,0,0,1,29.4,53Z';
+
+export const mojoDataSet = new Map<string, string>([
+    ['_viewbox', '0 0 100 100'],
+
+    ['m_cloud', 'M62,48.8H61.5a1.8,1.8,0,0,1-1.3-2.3,11,11,0,0,' +
+    '0-21.1-6.1,1.8,1.8,0,1,1-3.5-1,14.7,14.7,0,0,1,28.2,8.1' +
+    'A1.8,1.8,0,0,1,62,48.8ZM70.6,71.2H28.3' +
+    'A14.7,14.7,0,1,1,38.4,45.2,1.8,1.8,0,1,1,36,48' +
+    'a11,11,0,1,0-7.5,19.4H71.8A11,11,0,0,0,71,45.5' +
+    'a10.9,10.9,0,0,0-3.2.5,1.8,1.8,0,1,1-1.1-3.5,14.7,14.7,0,0,1,19,14' +
+    'A14.8,14.8,0,0,1,72.2,71.1H70.6Z'],
+
+    ['m_map', 'M50,17.6A32.4,32.4,0,1,0,82.4,50,32.4,32.4,0,0,0,50,17.6Z' +
+    'm0,61.1A28.7,28.7,0,1,1,78.7,50,28.7,28.7,0,0,1,50,78.7Z' +
+    'M75.9,48.8a1.8,1.8,0,0,1-1.8,1.8H65' +
+    'a38.3,38.3,0,0,1-8.4,22.9,1.8,1.8,0,0,1-1.4.7,1.8,1.8,0,0,' +
+    '1-1.2-.4,1.8,1.8,0,0,1-.3-2.6,34.6,34.6,0,0,0,7.5-20.5H39.2' +
+    'a34.5,34.5,0,0,0,7.6,20.7,1.8,1.8,0,0,1-1.4,3,1.8,1.8,0,0,' +
+    '1-1.4-.7,38.2,38.2,0,0,1-8.5-23H26.2a1.8,1.8,0,1,1,0-3.7' +
+    'h9.4a38.1,38.1,0,0,1,8.4-21.6,1.8,1.8,0,0,1,2.9,2.3,34.4,34.4,0,0,' +
+    '0-7.6,19.3h22a34.3,34.3,0,0,0-8-19.7,1.8,1.8,0,1,1,2.8-2.4,38,38,' +
+    '0,0,1,8.8,22.1h9.1A1.8,1.8,0,0,1,75.9,48.8Z'],
+
+    ['m_selectMap', 'M51.36,8.74A32.45,32.45,0,0,0,19,41.15' +
+    'a32.12,32.12,0,0,0,9.22,22.62L17,72.07a1.84,1.84,0,0,0,1,3.32' +
+    'L35.52,76h0l10,14.42a1.84,1.84,0,0,0,1.52.79,2.05,2.05,0,0,' +
+    '0,.49-0.06,1.84,1.84,0,0,0,1.35-1.66l2.68-39.19' +
+    'a1.73,1.73,0,0,0-.06-0.6,0.85,0.85,0,0,0-.09-0.24,1.7,1.7,0,0,' +
+    '0-.81-0.9l-0.18-.1a1.69,1.69,0,0,0-.94-0.16H49.33l-0.16,0' +
+    'a1,1,0,0,0-.31.12,1.52,1.52,0,0,0-.33.18L42.73,53' +
+    'a34.6,34.6,0,0,1-2.22-11.21H62.68a34.55,34.55,0,0,1-7.55,20.54' +
+    'A1.85,1.85,0,1,0,58,64.63a38.26,38.26,0,0,0,8.37-22.86h9.08' +
+    'a1.85,1.85,0,0,0,0-3.7H66.3a38.06,38.06,0,0,0-8.83-22.14,' +
+    '1.85,1.85,0,1,0-2.82,2.38,34.37,34.37,0,0,1,8,19.76h-22' +
+    'a34.38,34.38,0,0,1,7.58-19.3,1.85,1.85,0,1,0-2.87-2.33,' +
+    '38.11,38.11,0,0,0-8.41,21.63H27.53a1.85,1.85,0,0,0,0,3.7' +
+    'h9.28a38.43,38.43,0,0,0,2.85,13.48l-8.5,6.31a28.71,28.71,0,1,' +
+    '1,23.21,8.16,1.85,1.85,0,0,0,.19,3.68h0.19A32.41,32.41,0,0,' +
+    '0,51.36,8.74Zm-4,49.75L45.57,84l-6.85-9.87,2.64-4.92,0.56-1,2.8-5' +
+    'C45.61,61.58,46.49,60,47.31,58.49ZM44,56.63' +
+    'c-0.81,1.5-1.69,3.11-2.56,4.73l-3.3,6.11-0.19.35' +
+    'C37,69.4,36.19,70.93,35.4,72.34l-12-.44Z'],
+
+    ['thatsNoMoon', 'M50,83.4A33.2,33.2,0,1,1,83.2,50.2,33.2,33.2,0,0,' +
+    '1,50,83.4ZM79.3,50.1A29.3,29.3,0,1,0,50.1,79.4,29.3,29.3,0,0,0,' +
+    '79.3,50.1ZM65.4,46.9h9.1A1.9,1.9,0,0,1,76.4,48a1.9,1.9,0,0,' +
+    '1-.3,2.1,2.1,2.1,0,0,1-1.8.7H65.4c-0.1.6-.1,1.2-0.2,1.8' +
+    'A38.5,38.5,0,0,1,57,73.9a2.1,2.1,0,0,1-2.2.9,2,2,0,0,' +
+    '1-1.4-1.6,2.3,2.3,0,0,1,.6-1.7,33.6,33.6,0,0,0,4.9-8.5,34.6,34.6,' +
+    '0,0,0,2.5-11c0-.3,0-0.7,0-1.1H38.9c0.2,1.3.3,2.6,0.5,3.9' +
+    'a34.2,34.2,0,0,0,7.3,17,2,2,0,1,1-3,2.4A37.1,37.1,0,0,1,39.1,67' +
+    'a40.8,40.8,0,0,1-4-15.5V50.8H25.8a2,2,0,0,1-2.2-1.9,1.9,1.9,0,0,' +
+    '1,2.1-2H35l0.3-1.8-0.8-.2a7.5,7.5,0,0,1-5.5-8.5,12.4,12.4,0,0,' +
+    '1,10-10.3,15.5,15.5,0,0,1,3.4,0,0.6,0.6,0,0,0,.7-0.3l0.8-1.1' +
+    'a1.9,1.9,0,0,1,2.5-.4,1.8,1.8,0,0,1,.7,2.4,13.6,13.6,0,0,' +
+    '1-.8,1.4,7.7,7.7,0,0,1,2.1,6.3A11,11,0,0,1,46,40.2a12.6,12.6,0,0,' +
+    '1-6.3,4.5,0.5,0.5,0,0,0-.5.6c0,0.5-.1,1-0.1,1.6H61.5l-0.7-4' +
+    'A33.6,33.6,0,0,0,53.5,27c-0.8-1-.9-1.7-0.4-2.5a1.7,1.7,0,0,' +
+    '1,2.4-.7,3.6,3.6,0,0,1,1.1.9,37,37,0,0,1,8,17.1' +
+    'c0.3,1.5.4,3,.7,4.4v0.7Zm-28.8-4A10.1,10.1,0,0,0,46,34.1' +
+    'a5.3,5.3,0,0,0-6-5.8A10.2,10.2,0,0,0,31.3,36' +
+    'C30.4,39.9,32.8,42.9,36.6,42.9ZM34.9,35.1a4,4,0,0,' +
+    '1,2.7-3.2,2.7,2.7,0,0,1,3.8,2.6,4.4,4.4,0,0,1-2.5,4' +
+    'C36.8,39.5,34.7,38,34.9,35.1Zm2,0.7c0,0.7.3,1,.9,0.9' +
+    'a2.3,2.3,0,0,0,1.5-2.3,0.7,0.7,0,0,0-1.1-.6' +
+    'A2.2,2.2,0,0,0,36.9,35.8Z'],
+
+    ['m_ports', 'M83.2,20L80,16.8a4.8,4.8,0,0,0-6.8,0l-1.4,1.4' +
+    'a4.8,4.8,0,0,0-1.4,3.4l-4.5,5.9a3.8,3.8,0,0,0,.4,5l1.2,1.2' +
+    'a3.8,3.8,0,0,0,5,.4l5.4-3.9,0.5-.6h0a4.8,4.8,0,0,0,3.4-1.4' +
+    'l1.4-1.4A4.8,4.8,0,0,0,83.2,20ZM70.3,31.1H70.1l-1.2-1.2' +
+    'a0.2,0.2,0,0,1,0-.2l3.3-4.4,2.6,2.6Zm10.3-6.9-1.4,1.4' +
+    'a1.1,1.1,0,0,1-1.6,0l-3.2-3.2a1.1,1.1,0,0,1,0-1.6l1.4-1.4' +
+    'a1.1,1.1,0,0,1,1.6,0l3.2,3.2A1.1,1.1,0,0,1,80.6,24.2Z' +
+    'M33.7,67.5l-1.2-1.2a3.8,3.8,0,0,0-5-.4l-5.9,4.5' +
+    'a4.8,4.8,0,0,0-3.4,1.4l-1.4,1.4a4.8,4.8,0,0,0,0,6.8L20,83.2' +
+    'a4.8,4.8,0,0,0,6.8,0l1.4-1.4a4.8,4.8,0,0,0,1.4-3.5l4.5-5.9' +
+    'A3.8,3.8,0,0,0,33.7,67.5ZM25.6,79.3l-1.4,1.4' +
+    'a1.2,1.2,0,0,1-1.6,0l-3.2-3.2a1.1,1.1,0,0,1,0-1.6l1.4-1.4' +
+    'a1.1,1.1,0,0,1,.8-0.3,1.1,1.1,0,0,1,.8.3l3.2,3.2' +
+    'A1.1,1.1,0,0,1,25.6,79.3Zm5.6-9-3.3,4.4-2.5-2.5,4.3-3.3h0.2' +
+    'l1.2,1.2A0.2,0.2,0,0,1,31.1,70.3ZM65.4,61.9a6.2,6.2,0,0,1-8.8,0' +
+    'L37.2,42.5A2.5,2.5,0,1,0,33.7,46l7,7a6.2,6.2,0,0,1,.4,8.3h0' +
+    'l-0.2.2-0.2.2-3.6,3.6a1.8,1.8,0,0,1-2.6-2.6l3.6-3.6h0.1' +
+    'a2.5,2.5,0,0,0-.1-3.4l-7-7a6.2,6.2,0,0,1,8.8-8.8L59.3,59.3' +
+    'a2.5,2.5,0,0,0,3.5-3.5l-6.2-6.2a6.2,6.2,0,0,1,0-8.8l6.1-6.1' +
+    'a1.8,1.8,0,0,1,2.6,2.6l-6.1,6.1a2.5,2.5,0,0,0,0,3.5l6.2,6.2' +
+    'A6.2,6.2,0,0,1,65.4,61.9Z'],
+
+    ['m_switch', m_switch_arrows],
+
+    ['m_roadm', m_switch_arrows + m_octagon],
+
+    ['m_router', 'M29.3,60.9l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V55.2H21.4' +
+    'a1.8,1.8,0,0,1-1.8-1.8V46.7a1.8,1.8,0,0,1,1.8-1.8h3.2' +
+    'a1.8,1.8,0,0,1,0,3.7H23.2v3h6.1a1.8,1.8,0,0,1,1.8,1.8V56' +
+    'l11.1-5.9L31.1,44v2.7a1.8,1.8,0,0,1-3.7,0V40.8' +
+    'a1.8,1.8,0,0,1,2.7-1.6L47,48.5a1.8,1.8,0,0,1,0,3.2l-16.8,9Z' +
+    'M70.6,60.9l-0.9-.2L52.9,51.4a1.8,1.8,0,0,1,0-3.2l16.8-9' +
+    'a1.8,1.8,0,0,1,2.7,1.6v3.9h6.1a1.8,1.8,0,0,1,1.8,1.8v6.7' +
+    'a1.8,1.8,0,0,1-1.8,1.8H75.4a1.8,1.8,0,0,1,0-3.7h1.3v-3H70.6' +
+    'a1.8,1.8,0,0,1-1.8-1.8V43.9L57.7,49.8l11.1,6.1V53.2' +
+    'a1.8,1.8,0,0,1,3.7,0v5.8a1.8,1.8,0,0,1-.9,1.6Z' +
+    'M49.8,82.5h0a1.8,1.8,0,0,1-1.6-1l-9-16.8A1.8,1.8,0,0,1,40.8,62' +
+    'h3.9V55.9a1.8,1.8,0,0,1,1.8-1.8h6.7a1.8,1.8,0,0,1,1.8,1.8v3.2' +
+    'a1.8,1.8,0,0,1-3.7,0V57.8h-3v6.1a1.8,1.8,0,0,1-1.8,1.8H43.9' +
+    'l5.9,11.1,6.1-11.1H53.2a1.8,1.8,0,0,1,0-3.7h5.8' +
+    'a1.8,1.8,0,0,1,1.6,2.7L51.4,81.5A1.8,1.8,0,0,1,49.8,82.5Z' +
+    'M53.3,45.8H46.7A1.8,1.8,0,0,1,44.8,44V40.8a1.8,1.8,0,0,1,3.7,0' +
+    'v1.3h3V36a1.8,1.8,0,0,1,1.8-1.8H56L50.1,23.1,44,34.2h2.7' +
+    'a1.8,1.8,0,0,1,0,3.7H40.8a1.8,1.8,0,0,1-1.6-2.7l9.2-16.8' +
+    'a1.8,1.8,0,0,1,1.6-1h0a1.8,1.8,0,0,1,1.6,1l9,16.8' +
+    'a1.8,1.8,0,0,1-1.6,2.7H55.2V44A1.8,1.8,0,0,1,53.3,45.8Z' +
+    'M50,91.2A41.3,41.3,0,1,1,91.2,50,41.3,41.3,0,0,1,50,91.2Z' +
+    'm0-78.9A37.6,37.6,0,1,0,87.6,50,37.6,37.6,0,0,0,50,12.4Z'],
+
+    ['m_uiAttached', 'M73.6,61.3H26.4a4.9,4.9,0,0,1-4.9-4.9V27.7' +
+    'a4.9,4.9,0,0,1,4.9-4.9H73.6a4.9,4.9,0,0,1,4.9,4.9V56.5' +
+    'A4.9,4.9,0,0,1,73.6,61.3ZM26.4,26.5a1.2,1.2,0,0,0-1.2,1.2' +
+    'V56.5a1.2,1.2,0,0,0,1.2,1.2H73.6a1.2,1.2,0,0,0,1.2-1.2V27.7' +
+    'a1.2,1.2,0,0,0-1.2-1.2H26.4ZM63.5,75.3a1.8,1.8,0,0,1-1.8,1.8' +
+    'H38.4a1.8,1.8,0,0,1,0-3.7h9.8V65.7a1.8,1.8,0,0,1,3.7,0v7.8' +
+    'h9.8A1.8,1.8,0,0,1,63.5,75.3Z'],
+
+    ['m_office', 'M31.7,28.6h-6a1.8,1.8,0,1,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,31.7,28.6ZM45,28.6h-6a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,1,' +
+    '1,45,28.6ZM31.7,38.3h-6a1.8,1.8,0,1,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,31.7,38.3ZM45,38.3h-6a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,1,' +
+    '1,45,38.3ZM31.7,48.1h-6a1.8,1.8,0,1,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,31.7,48.1ZM45,48.1h-6a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,1,' +
+    '1,45,48.1ZM63.7,51.1h-6a1.8,1.8,0,1,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,63.7,51.1ZM77,51.1H71a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,77,51.1ZM63.7,60.9h-6a1.8,1.8,0,1,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,63.7,60.9ZM77,60.9H71a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,0,' +
+    '1,77,60.9ZM45,57.9h-6a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,1,1,' +
+    '45,57.9ZM45,67.6h-6a1.8,1.8,0,0,1,0-3.7h6A1.8,1.8,0,1,1,45,67.6Z' +
+    'M82.3,37.9H52.6V18a1.8,1.8,0,0,0-1.8-1.8H19.2A1.8,1.8,0,0,' +
+    '0,17.3,18V50.1a1.8,1.8,0,0,0,3.7,0V19.8H48.9V80.2H27.2V75.4' +
+    'c4-1.2,6.5-3.3,7.3-6.3,2-7.2-6.8-16.2-7.8-17.2a1.9,1.9,0,0,' +
+    '0-2.6,0c-1,1-9.9,10-7.9,17.2,0.8,3,3.3,5.1,7.3,6.3v4.7H21V77.9' +
+    'a1.8,1.8,0,0,0-3.7,0V82a1.8,1.8,0,0,0,1.9,1.8H82.3A1.8,1.8,0,0,' +
+    '0,84.1,82V39.7A1.8,1.8,0,0,0,82.3,37.9ZM25.4,62.5a1.9,1.9,0,0,' +
+    '0-1.9,1.8v7.2c-2.1-.8-3.4-1.9-3.8-3.4-1-3.7,3-9.2,5.6-12.2,2.6,' +
+    '3,6.6,8.5,5.6,12.2-0.4,1.5-1.7,2.6-3.8,3.4V64.4A1.8,1.8,0,0,' +
+    '0,25.4,62.5ZM71.5,80.2H63.3V70h8.2V80.2Zm8.9,0H75.2V68.1' +
+    'a1.8,1.8,0,0,0-1.8-1.8H61.5a1.8,1.8,0,0,0-1.8,1.8V80.2H52.6' +
+    'V41.6H80.4V80.2Z'],
+
+    ['m_home', 'M79.2,52.2a1.7,1.7,0,0,1-2.3,0l-5.8-5.8V77a1.7,1.7,0,0,' +
+    '1-1.7,1.7H30.6A1.7,1.7,0,0,1,28.9,77V52.1a1.7,1.7,0,1,1,3.3,0' +
+    'V75.3H67.8V43.8a1.7,1.7,0,0,1,.1-0.7L50.1,25.4l-26.9,27' +
+    'a1.7,1.7,0,0,1-1.2.5A1.7,1.7,0,0,1,20.8,50L48.9,21.8' +
+    'a1.7,1.7,0,0,1,2.4,0l28,28A1.7,1.7,0,0,1,79.2,52.2ZM57.1,61.6' +
+    'H42.9a1.7,1.7,0,0,1-1.7-1.7V45.6A1.7,1.7,0,0,1,42.9,44H57.1' +
+    'a1.7,1.7,0,0,1,1.7,1.7V59.9A1.7,1.7,0,0,1,57.1,61.6ZM44.5,58.2' +
+    'H55.5V47.3H44.5V58.2Z'],
+
+    ['m_summary', 'M73.9,79.9H26.1A4.9,4.9,0,0,1,21.2,75V25' +
+    'a4.9,4.9,0,0,1,4.9-4.9H73.9A4.9,4.9,0,0,1,78.8,25V75' +
+    'A4.9,4.9,0,0,1,73.9,79.9Zm-47.8-56A1.2,1.2,0,0,0,24.9,25V75' +
+    'a1.2,1.2,0,0,0,1.2,1.2H73.9A1.2,1.2,0,0,0,75.1,75V25' +
+    'a1.2,1.2,0,0,0-1.2-1.2H26.1ZM42.4,46.7h-8a4.9,4.9,0,0,1-4.9-4.9' +
+    'v-8A4.9,4.9,0,0,1,34.4,29h8a4.9,4.9,0,0,1,4.9,4.9v8' +
+    'A4.9,4.9,0,0,1,42.4,46.7Zm-8-14.1a1.2,1.2,0,0,0-1.2,1.2v8' +
+    'A1.2,1.2,0,0,0,34.4,43h8a1.2,1.2,0,0,0,1.2-1.2v-8' +
+    'a1.2,1.2,0,0,0-1.2-1.2h-8ZM68.7,57.3H31.3a1.8,1.8,0,0,1,0-3.7' +
+    'H68.7A1.8,1.8,0,0,1,68.7,57.3ZM68.7,66.5H31.3a1.8,1.8,0,0,1,0-3.7' +
+    'H68.7A1.8,1.8,0,0,1,68.7,66.5Z'],
+
+    ['m_details', 'M68.7,33.2H31.3a1.8,1.8,0,0,1,0-3.7H68.7' +
+    'A1.8,1.8,0,1,1,68.7,33.2ZM73.9,17.5H26.1a4.9,4.9,0,0,0-4.9,4.9' +
+    'V72.4a4.9,4.9,0,0,0,4.9,4.9h8.2l-4.1,6.6a1.9,1.9,0,0,0,.6,2.5' +
+    'l1,0.3a1.8,1.8,0,0,0,1.6-.9L46.1,64.9a15.1,15.1,0,0,' +
+    '0,4,.5,15.6,15.6,0,0,0,3.7-.4A15.9,15.9,0,0,0,57,63.9H68.7' +
+    'a1.8,1.8,0,0,0,0-3.7H61.9a16.6,16.6,0,0,0,1.6-2.2,15.5,15.5,0,0,' +
+    '0,2.2-9.4h2.9a1.8,1.8,0,0,0,0-3.7H65a15.7,15.7,0,0,0-29.8,0' +
+    'H31.3a1.8,1.8,0,1,0,0,3.7h3.2a15.7,15.7,0,0,0,.4,4.9,15.5,15.5,' +
+    '0,0,0,3.5,6.7H31.3a1.8,1.8,0,1,0,0,3.7H42.4l-6,9.8H26.1' +
+    'a1.2,1.2,0,0,1-1.2-1.2V22.4a1.2,1.2,0,0,1,1.2-1.2H73.9' +
+    'a1.2,1.2,0,0,1,1.2,1.2V72.4a1.2,1.2,0,0,1-1.2,1.2H44.5' +
+    'a1.8,1.8,0,0,0,0,3.7H73.9a4.9,4.9,0,0,0,4.9-4.9V22.4' +
+    'A4.9,4.9,0,0,0,73.9,17.5ZM38.5,52.6A12,12,0,0,1,50.2,37.8,12,12,' +
+    '0,0,1,61.8,47a10.7,10.7,0,0,1,.3,1.6,12,12,0,0,1-5.9,11.6,12,12,' +
+    '0,0,1-12,0L43.9,60A12,12,0,0,1,38.5,52.6Z'],
+
+    ['m_oblique', 'M82.1,30.5a1.8,1.8,0,0,0-1.7-1.1H30.2' +
+    'a1.8,1.8,0,0,0-1.4.7L18.2,42.8a1.8,1.8,0,0,0,1.4,3H40.9V62.2' +
+    'a1.8,1.8,0,1,0,3.7,0V45.8H55.4V62.2a1.9,1.9,0,1,0,3.7,0V45.8' +
+    'H69.8a1.9,1.9,0,0,0,1.4-.7L81.8,32.5A1.8,1.8,0,0,0,82.1,30.5Z' +
+    'M69,42.2H23.5l7.5-9H76.5ZM69.8,70.5H19.6a1.8,1.8,0,0,1-1.4-3' +
+    'L28.7,54.8a1.8,1.8,0,0,1,1.4-.7h7a1.8,1.8,0,0,1,0,3.7H31l-7.5,9' +
+    'H69l7.5-9H62.4a1.8,1.8,0,0,1,0-3.7H80.4a1.8,1.8,0,0,1,1.4,3' +
+    'L71.3,69.9A1.8,1.8,0,0,1,69.8,70.5ZM52.3,57.8H47.6' +
+    'a1.8,1.8,0,0,1,0-3.7h4.8A1.8,1.8,0,0,1,52.3,57.8Z'],
+
+    ['m_filters', 'M69.9,45.8H19.5a1.9,1.9,0,0,1-1.4-3L28.7,30' +
+    'a1.8,1.8,0,0,1,1.4-.7H80.5a1.8,1.8,0,0,1,1.4,3L71.3,45.1' +
+    'A1.8,1.8,0,0,1,69.9,45.8ZM23.5,42.1H69l7.5-9H31ZM69.9,58.2' +
+    'H19.5a1.8,1.8,0,0,1-1.4-3l6.1-7.3a1.8,1.8,0,0,1,2.8,2.4l-3.6,4.3' +
+    'H69l7.6-9.1a1.8,1.8,0,0,1,.5-3.6h3.4a1.8,1.8,0,0,1,1.4,3' +
+    'L71.3,57.5A1.8,1.8,0,0,1,69.9,58.2ZM69.9,70.7H19.5' +
+    'a1.9,1.9,0,0,1-1.4-3l5.6-6.7a1.8,1.8,0,0,1,2.8,2.4L23.5,67H69' +
+    'l7.5-9H76.3a1.8,1.8,0,0,1,0-3.7h4.1a1.9,1.9,0,0,1,1.4,3L71.3,70' +
+    'A1.8,1.8,0,0,1,69.9,70.7Z'],
+
+    ['m_cycleLabels', 'M78.5,74.7a34.2,34.2,0,0,1-47.7,6.8l-0.3-.3' +
+    'L30.4,81V80.8a1.8,1.8,0,0,1,.8-2.5l0.7-.3-5.2-3.4v6.2l0.7-.3' +
+    'a1.8,1.8,0,1,1,1.7,3.3l-3.4,1.8-0.9.2-1-.3a1.9,1.9,0,0,1-.9-1.6' +
+    'V71.1a1.8,1.8,0,0,1,2.8-1.5l10.7,7a1.9,1.9,0,0,1,.8,1.6,1.9,1.9,' +
+    '0,0,1-1,1.5l-0.7.4a30.5,30.5,0,0,0,40.1-7.7A1.8,1.8,0,0,' +
+    '1,78.5,74.7ZM30.8,25.7L29.5,38.4a1.8,1.8,0,0,1-1.1,1.5l-0.8.2' +
+    'a1.9,1.9,0,0,1-1.1-.3l-1.7-1.2a30.1,30.1,0,0,0-2.7,6,1.9,1.9,0,0,' +
+    '1-1.8,1.3H19.9a1.8,1.8,0,0,1-1.2-2.3A33.9,33.9,0,0,1,22.8,35' +
+    'a1.8,1.8,0,0,1,1.6-.8,1.9,1.9,0,0,1,1.2.3L26.2,35l0.7-6.2-5.5,2.8' +
+    'L21.9,32a1.8,1.8,0,1,1-2.1,3l-3.1-2.2a1.8,1.8,0,0,1,.2-3.2' +
+    'l11.3-5.8A1.8,1.8,0,0,1,30.8,25.7ZM85.2,30.8L84.7,43.4' +
+    'a1.8,1.8,0,0,1-1,1.6l-0.8.2a1.8,1.8,0,0,1-1.1-.4L71.4,37.4' +
+    'a1.8,1.8,0,0,1,.3-3.2l1.9-.9a30.5,30.5,0,0,0-3.9-5.3,1.8,1.8,0,0,' +
+    '1,2.7-2.5,34.3,34.3,0,0,1,5.3,7.7,2,2,0,0,1-.9,2.6' +
+    'l-0.7.3,5.1,3.6,0.3-6.2-0.7.3a1.8,1.8,0,0,1-1.6-3.3L82.6,29' +
+    'a1.8,1.8,0,0,1,1.8.1A1.9,1.9,0,0,1,85.2,30.8ZM62.4,32.2H40.2' +
+    'a4.9,4.9,0,0,1-4.9-4.9V16.6a4.9,4.9,0,0,1,4.9-4.9H62.4' +
+    'a4.9,4.9,0,0,1,4.9,4.9V27.3A4.9,4.9,0,0,1,62.4,32.2ZM40.2,15.4' +
+    'A1.2,1.2,0,0,0,39,16.6V27.3a1.2,1.2,0,0,0,1.2,1.2H62.4' +
+    'a1.2,1.2,0,0,0,1.2-1.2V16.6a1.2,1.2,0,0,0-1.2-1.2H40.2Z' +
+    'M88.4,68.1H66.2a4.9,4.9,0,0,1-4.9-4.9V52.6a4.9,4.9,0,0,1,4.9-4.9' +
+    'H88.4a4.9,4.9,0,0,1,4.9,4.9V63.2A4.9,4.9,0,0,1,88.4,68.1Z' +
+    'M66.2,51.4A1.2,1.2,0,0,0,65,52.6V63.2a1.2,1.2,0,0,0,1.2,1.2H88.4' +
+    'a1.2,1.2,0,0,0,1.2-1.2V52.6a1.2,1.2,0,0,0-1.2-1.2H66.2Z' +
+    'M33.8,68.1H11.6a4.9,4.9,0,0,1-4.9-4.9V52.6a4.9,4.9,0,0,1,4.9-4.9' +
+    'H33.8a4.9,4.9,0,0,1,4.9,4.9V63.2A4.9,4.9,0,0,1,33.8,68.1Z' +
+    'M11.6,51.4a1.2,1.2,0,0,0-1.2,1.2V63.2a1.2,1.2,0,0,0,1.2,1.2' +
+    'H33.8A1.2,1.2,0,0,0,35,63.2V52.6a1.2,1.2,0,0,0-1.2-1.2H11.6Z'],
+
+    ['m_prev', 'M59.8,72l-0.9-.2L21.8,51.3a1.8,1.8,0,0,1,0-3.2L58.9,28.2' +
+    'a1.8,1.8,0,0,1,2.7,1.6V40.7H77.3a1.8,1.8,0,0,1,1.8,1.8V57.3' +
+    'a1.8,1.8,0,0,1-1.8,1.8h-7a1.8,1.8,0,1,1,0-3.7h5.2v-11H59.8' +
+    'A1.8,1.8,0,0,1,58,42.6V33L26.6,49.7,58,67V57.3' +
+    'a1.8,1.8,0,0,1,3.7,0V70.1a1.8,1.8,0,0,1-.9,1.6Z'],
+
+    ['m_next', 'M40.2,72l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V57.3' +
+    'a1.8,1.8,0,0,1,3.7,0V67L73.5,49.7,42,32.9v9.6' +
+    'a1.8,1.8,0,0,1-1.8,1.8H24.5v11h5.2a1.8,1.8,0,1,1,0,3.7h-7' +
+    'a1.8,1.8,0,0,1-1.8-1.8V42.6a1.8,1.8,0,0,1,1.8-1.8H38.3V29.9' +
+    'a1.8,1.8,0,0,1,2.7-1.6L78.2,48.1a1.8,1.8,0,0,1,0,3.2L41.1,71.8Z'],
+
+    ['m_flows', 'M50.1,26.2a7.4,7.4,0,1,1,7.4-7.4A7.4,7.4,0,0,1,50.1,26.2Z' +
+    'm0-11.2a3.8,3.8,0,1,0,3.8,3.8A3.8,3.8,0,0,0,50.1,15Z' +
+    'M50.1,88.6a7.4,7.4,0,1,1,7.4-7.4A7.4,7.4,0,0,1,50.1,88.6Z' +
+    'm0-11.2a3.8,3.8,0,1,0,3.8,3.8A3.8,3.8,0,0,0,50.1,77.4Z' +
+    'M72,50.1a1.8,1.8,0,0,1-1.8,1.8H58.1V55a3,3,0,0,1-3,3H51.9V70.2' +
+    'a1.8,1.8,0,0,1-3.6,0V58.1h-3a3,3,0,0,1-3-3V51.9H29.8' +
+    'a1.8,1.8,0,1,1,0-3.6H42.3v-3a3,3,0,0,1,3-3h3a1.7,1.7,0,0,1,0-.3' +
+    'V29.8a1.8,1.8,0,0,1,3.6,0V41.9a1.7,1.7,0,0,1,0,.3h3.2' +
+    'a3,3,0,0,1,3,3v3H70.2A1.8,1.8,0,0,1,72,50.1ZM18.8,57.5' +
+    'a7.4,7.4,0,1,1,7.4-7.4A7.4,7.4,0,0,1,18.8,57.5Zm0-11.2' +
+    'a3.8,3.8,0,1,0,3.8,3.8A3.8,3.8,0,0,0,18.8,46.3ZM81.2,57.5' +
+    'a7.4,7.4,0,1,1,7.4-7.4A7.4,7.4,0,0,1,81.2,57.5Zm0-11.2' +
+    'A3.8,3.8,0,1,0,85,50.1,3.8,3.8,0,0,0,81.2,46.3Z'],
+
+    ['m_allTraffic', m_diamond + m_trafficArrows],
+
+    ['m_xMark', 'M76.8,73.7a2.2,2.2,0,0,1-3.1,3.1L50,53.1,26.3,76.7' +
+    'a2.2,2.2,0,1,1-3.1-3.1L46.9,50,23.2,26.3a2.2,2.2,0,0,1,3.1-3.1' +
+    'L50,46.9,73.7,23.2a2.2,2.2,0,1,1,3.1,3.1L53.1,50Z'],
+
+    ['m_resetZoom', 'M73.9,76.8H64.2a1.8,1.8,0,1,1,0-3.7h9.7' +
+    'a1.2,1.2,0,0,0,1.2-1.2V62.6a1.8,1.8,0,0,1,3.7,0v9.3' +
+    'A4.9,4.9,0,0,1,73.9,76.8ZM77,33.3a1.8,1.8,0,0,1-1.8-1.8V22' +
+    'a1.2,1.2,0,0,0-1.2-1.2H64.2a1.8,1.8,0,1,1,0-3.7h9.7' +
+    'A4.9,4.9,0,0,1,78.8,22v9.5A1.8,1.8,0,0,1,77,33.3ZM23,33.6' +
+    'a1.8,1.8,0,0,1-1.8-1.8V22a4.9,4.9,0,0,1,4.9-4.9h9.8' +
+    'a1.8,1.8,0,0,1,0,3.7H26.1A1.2,1.2,0,0,0,24.9,22v9.7' +
+    'A1.8,1.8,0,0,1,23,33.6ZM65.3,42.3A15.7,15.7,0,1,0,42.6,59.8' +
+    'L34.4,73.1H26.1a1.2,1.2,0,0,1-1.2-1.2V62.1a1.9,1.9,0,0,0-3.7,0' +
+    'v9.8a4.9,4.9,0,0,0,4.9,4.9h6.1l-2,3.3' +
+    'a1.8,1.8,0,0,0,.6,2.5,1.8,1.8,0,0,0,1,.3,1.8,1.8,0,0,0,1.6-.9' +
+    'L46,61.2a15.7,15.7,0,0,0,7.7.1A15.7,15.7,0,0,0,65.3,42.3Z' +
+    'm-5,9.9A12,12,0,1,1,50.1,34a12,12,0,0,1,11.7,9.2' +
+    'A11.9,11.9,0,0,1,60.3,52.3Z'],
+
+    ['m_eqMaster', 'M63,79.9H37.4a1.8,1.8,0,0,1-1.2-3.2L48.8,65.1' +
+    'a1.8,1.8,0,0,1,2.5,0L64.2,76.7A1.8,1.8,0,0,1,63,79.9Z' +
+    'M42.1,76.2H58.2l-8.1-7.3ZM19.7,65.8a1.8,1.8,0,0,1-.3-3.7' +
+    'l61-11.3a1.8,1.8,0,1,1,.7,3.6L20,65.8H19.7ZM34.2,53.5' +
+    'A16.7,16.7,0,1,1,50.9,36.8,16.7,16.7,0,0,1,34.2,53.5Zm0-29.7' +
+    'a13,13,0,1,0,13,13A13,13,0,0,0,34.2,23.8ZM70.7,45.7' +
+    'a8.6,8.6,0,1,1,8.6-8.6A8.6,8.6,0,0,1,70.7,45.7Zm0-13.6' +
+    'a4.9,4.9,0,1,0,4.9,4.9A4.9,4.9,0,0,0,70.7,32.2Z'],
+
+    ['m_unknown', 'M63.2,20.6H36.8A16.2,16.2,0,0,0,20.6,36.8V63.2' +
+    'A16.2,16.2,0,0,0,36.8,79.4H63.2A16.2,16.2,0,0,0,79.4,63.2V36.8' +
+    'A16.2,16.2,0,0,0,63.2,20.6ZM75.7,63.2A12.5,12.5,0,0,1,63.2,75.7' +
+    'H36.8A12.5,12.5,0,0,1,24.3,63.2V36.8A12.5,12.5,0,0,1,36.8,24.3' +
+    'H63.2A12.5,12.5,0,0,1,75.7,36.8V63.2ZM67.3,64.7' +
+    'a1.8,1.8,0,0,1-2.6,2.6L50,52.6,35.3,67.3a1.8,1.8,0,0,1-2.6-2.6' +
+    'L47.4,50,32.7,35.3a1.8,1.8,0,0,1,2.6-2.6L50,47.4,64.7,32.7' +
+    'a1.8,1.8,0,0,1,2.6,2.6L52.6,50Z'],
+
+    ['m_controller', 'M73.9,20.1H26.1A4.9,4.9,0,0,0,21.2,25V75' +
+    'a4.9,4.9,0,0,0,4.9,4.9H73.9A4.9,4.9,0,0,0,78.8,75V25' +
+    'A4.9,4.9,0,0,0,73.9,20.1ZM75.1,75a1.2,1.2,0,0,1-1.2,1.2H26.1' +
+    'A1.2,1.2,0,0,1,24.9,75V25a1.2,1.2,0,0,1,1.2-1.2H73.9' +
+    'A1.2,1.2,0,0,1,75.1,25V75ZM70.5,63a1.8,1.8,0,0,1-1.9,1.8H38.3' +
+    'v2.4a1.8,1.8,0,0,1-3.7,0V64.9H31.3a1.8,1.8,0,1,1,0-3.7h3.3V58.3' +
+    'a1.8,1.8,0,0,1,3.7,0v2.9H68.7A1.9,1.9,0,0,1,70.5,63ZM70.5,36.6' +
+    'a1.9,1.9,0,0,1-1.9,1.9H44.5v2.3a1.8,1.8,0,0,1-3.7,0V38.5H31.3' +
+    'a1.8,1.8,0,1,1,0-3.7h9.5v-3a1.8,1.8,0,0,1,3.7,0v3H68.7' +
+    'A1.8,1.8,0,0,1,70.5,36.6ZM70.5,49.8a1.9,1.9,0,0,1-1.9,1.8H60.9' +
+    'v2.1a1.8,1.8,0,1,1-3.7,0V51.7H31.3a1.8,1.8,0,1,1,0-3.7H57.2' +
+    'V44.8a1.8,1.8,0,1,1,3.7,0V48h7.8A1.9,1.9,0,0,1,70.5,49.8Z'],
+
+    ['m_virtual', 'M56.6,53.5l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V45.8' +
+    'a1.8,1.8,0,1,1,3.7,0v2.7l11.1-6.1L58.4,36.5v2.7' +
+    'A1.8,1.8,0,0,1,56.6,41H50.5v3h1.3a1.8,1.8,0,0,1,0,3.7H48.6' +
+    'a1.8,1.8,0,0,1-1.8-1.8V39.2a1.8,1.8,0,0,1,1.8-1.8h6.1V33.4' +
+    'a1.8,1.8,0,0,1,2.7-1.6l16.8,9a1.8,1.8,0,0,1,0,3.2L57.5,53.3Z' +
+    'M56.6,77.9l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V70.2a1.8,1.8,0,1,1,3.7,0' +
+    'v2.7l11.1-6.1L58.4,60.9v2.7a1.8,1.8,0,0,1-1.8,1.8H50.5v3h1.3' +
+    'a1.8,1.8,0,0,1,0,3.7H48.6a1.8,1.8,0,0,1-1.8-1.8V63.6' +
+    'a1.8,1.8,0,0,1,1.8-1.8h6.1V57.8a1.8,1.8,0,0,1,2.7-1.6l16.8,9' +
+    'a1.8,1.8,0,0,1,0,3.2L57.5,77.7ZM38.5,64.9l-0.9-.2L20.8,55.4' +
+    'a1.8,1.8,0,0,1,0-3.2l16.8-9a1.8,1.8,0,0,1,2.7,1.6v3.9h6.1' +
+    'a1.8,1.8,0,0,1,1.8,1.8v6.7a1.8,1.8,0,0,1-1.8,1.8H43.2' +
+    'a1.8,1.8,0,1,1,0-3.7h1.3v-3H38.5a1.8,1.8,0,0,1-1.8-1.8V47.9' +
+    'L25.6,53.8l11.1,6.1V57.2a1.8,1.8,0,0,1,3.7,0v5.8' +
+    'a1.8,1.8,0,0,1-.9,1.6ZM38.5,89.3l-0.9-.2L20.8,79.8' +
+    'a1.8,1.8,0,0,1,0-3.2l16.8-9a1.8,1.8,0,0,1,2.7,1.6v3.9h6.1' +
+    'A1.8,1.8,0,0,1,48.3,75v6.7a1.8,1.8,0,0,1-1.8,1.8H43.2' +
+    'a1.8,1.8,0,1,1,0-3.7h1.3v-3H38.5A1.8,1.8,0,0,1,36.6,75V72.3' +
+    'L25.6,78.2l11.1,6.1V81.6a1.8,1.8,0,1,1,3.7,0v5.8' +
+    'a1.8,1.8,0,0,1-.9,1.6ZM60.8,29.1H60.3A1.8,1.8,0,0,1,59,26.8' +
+    'a9.7,9.7,0,0,0-18.7-5.4,1.8,1.8,0,1,1-3.5-1,13.4,13.4,0,0,' +
+    '1,25.8,7.4A1.8,1.8,0,0,1,60.8,29.1ZM77.4,45.7a1.8,1.8,0,0,' +
+    '1-1.3-3.1,9.7,9.7,0,0,0-9.9-16A1.8,1.8,0,1,1,65,23.1,13.4,13.4,' +
+    '0,0,1,78.7,45.1,1.8,1.8,0,0,1,77.4,45.7ZM22.7,45.8a1.8,1.8,0,0,' +
+    '1-1.3-.6A13.4,13.4,0,0,1,39.6,25.6a1.8,1.8,0,1,1-2.4,2.8' +
+    'A9.7,9.7,0,0,0,24,42.6,1.8,1.8,0,0,1,22.7,45.8Z'],
+
+
+    ['m_other', 'M78.9,64.9H21.1A4.9,4.9,0,0,1,16.2,60V24.3a4.9,4.9,0,0,' +
+    '1,4.9-4.9H78.9a4.9,4.9,0,0,1,4.9,4.9V60A4.9,4.9,0,0,1,78.9,64.9Z' +
+    'M21.1,23.1a1.2,1.2,0,0,0-1.2,1.2V60a1.2,1.2,0,0,0,1.2,1.2H78.9' +
+    'A1.2,1.2,0,0,0,80.1,60V24.3a1.2,1.2,0,0,0-1.2-1.2H21.1Z' +
+    'M65.8,78.8a1.9,1.9,0,0,1-1.8,1.8H36.1a1.9,1.9,0,1,1,0-3.7H48.2' +
+    'V70.4a1.8,1.8,0,1,1,3.7,0v6.5H63.9A1.9,1.9,0,0,1,65.8,78.8Z' +
+    'M47.2,49.3V48.1c-0.3-2.3.5-4.9,2.7-7.5s3-4,3-5.9-1.4-3.7-4.1-3.7' +
+    'a7.7,7.7,0,0,0-4.4,1.3l-1-2.7A11.3,11.3,0,0,1,49.5,28' +
+    'c5,0,7.2,3.1,7.2,6.3s-1.6,5-3.7,7.5-2.6,4.1-2.5,6.3v1.1H47.2Z' +
+    'm-1,6a2.5,2.5,0,0,1,2.6-2.7A2.7,2.7,0,1,1,46.3,55.3Z'],
+
+    ['m_endstation', 'M75,49.5H25a1.8,1.8,0,0,1-1.8-1.8V27.1' +
+    'A1.8,1.8,0,0,1,25,25.3H75a1.8,1.8,0,0,1,1.8,1.8V47.7' +
+    'A1.8,1.8,0,0,1,75,49.5ZM26.9,45.8H73.1V28.9H26.9V45.8Z' +
+    'M35.5,43.2H30.7a1.8,1.8,0,1,1,0-3.7h4.8A1.8,1.8,0,1,1,35.5,43.2Z' +
+    'M72.1,72.9a1.8,1.8,0,0,1-1.8,1.8H29.7a1.8,1.8,0,1,1,0-3.7' +
+    'H48.2V53.5a1.8,1.8,0,1,1,3.7,0V71.1H70.3A1.9,1.9,0,0,1,72.1,72.9Z'],
+
+    ['m_bgpSpeaker', 'M59.2,49.6l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V43.3' +
+    'a1.8,1.8,0,1,1,3.7,0v1.3l7-3.9L61,37v1.3a1.8,1.8,0,0,1-1.8,1.8' +
+    'H47.5a1.8,1.8,0,1,1,0-3.7h9.8V33.9A1.8,1.8,0,0,1,60,32.3' +
+    'l12.8,6.8a1.8,1.8,0,0,1,0,3.2l-12.8,7Z' +
+    'M40,58.8l-0.9-.2-12.8-7a1.8,1.8,0,0,1,0-3.2l12.8-6.8' +
+    'a1.8,1.8,0,0,1,2.7,1.6v2.5h9.8a1.8,1.8,0,0,1,0,3.7H40' +
+    'a1.8,1.8,0,0,1-1.8-1.8V46.2l-7,3.8,7,3.9V52.5' +
+    'a1.8,1.8,0,0,1,3.7,0v4.4a1.8,1.8,0,0,1-.9,1.6Z' +
+    'M83.6,45.8c0,13.8-15.1,25-33.6,25a43.8,43.8,0,0,1-6.1-.4' +
+    'c-2.5,2.7-7.2,6.1-15.6,8.7H27.8a1.8,1.8,0,0,1-1.2-3.2' +
+    's5.4-5,5.8-10.2a1.8,1.8,0,0,1,2-1.7A1.8,1.8,0,0,1,36,66' +
+    'a16.2,16.2,0,0,1-2.5,7.2,24.4,24.4,0,0,0,8.3-5.9L42,67l0.2-.2' +
+    'h0l0.6-.2h0.6a41.4,41.4,0,0,0,6.5.5c16.5,0,29.9-9.5,29.9-21.3' +
+    'S66.5,24.5,50,24.5,20.1,34.1,20.1,45.8c0,5.4,2.9,10.6,8.2,14.6' +
+    'a1.8,1.8,0,0,1-2.2,2.9' +
+    'c-6.2-4.7-9.7-10.9-9.7-17.5,0-13.8,15.1-25,33.6-25' +
+    'S83.6,32,83.6,45.8Z'],
+
+    ['m_otn', m_otn_base],
+
+    ['m_roadm_otn', m_otn_base + m_octagon],
+
+    ['m_fiberSwitch', 'M47.5,37.2a1.8,1.8,0,0,1-1.8-1.8V25.6H43.4' +
+    'a1.8,1.8,0,0,1-1.6-2.7l6.4-12a1.8,1.8,0,0,1,1.6-1h0' +
+    'a1.8,1.8,0,0,1,1.6,1l6.6,12a1.8,1.8,0,0,1-1.6,2.7H53.2' +
+    'a1.8,1.8,0,0,1,0-3.7h0.1l-3.5-6.3L46.5,22h1a1.8,1.8,0,0,1,1.8,1.8' +
+    'V35.3A1.8,1.8,0,0,1,47.5,37.2Z' +
+    'M75.9,46.9H75.8a1.8,1.8,0,0,1-1.5-1l-1.8-3.4' +
+    'a1.8,1.8,0,1,1,3.2-1.7l0.4,0.8,4.2-6-7.1-.3,0.5,0.9' +
+    'a1.8,1.8,0,0,1-.8,2.5l-10.4,5a1.8,1.8,0,0,1-1.6-3.3l8.7-4.2-1-2' +
+    'a1.8,1.8,0,0,1,.1-1.8,1.8,1.8,0,0,1,1.6-.8l13.6,0.5' +
+    'A1.8,1.8,0,0,1,85.3,35L77.4,46.1A1.8,1.8,0,0,1,75.9,46.9Z' +
+    'M81.2,72.5H81.1l-13.6-.8A1.8,1.8,0,0,1,66,69l1.7-3.1' +
+    'a1.8,1.8,0,1,1,3.2,1.8l-0.3.5,7.3,0.4-3.5-6.2-0.5.9' +
+    'a1.8,1.8,0,0,1-2.5.6l-9.8-6.1a1.8,1.8,0,0,1,1.9-3.1' +
+    'l8.2,5.1,1.2-1.9a1.9,1.9,0,0,1,1.6-.9,1.8,1.8,0,0,1,1.6.9' +
+    'l6.8,11.8A1.8,1.8,0,0,1,81.2,72.5Z' +
+    'M48.8,89.7a1.8,1.8,0,0,1-1.6-1l-6.6-12a1.8,1.8,0,0,1,1.6-2.7h3.3' +
+    'a1.8,1.8,0,0,1,0,3.7H45.3L48.7,84l3.4-6.3h-1' +
+    'a1.8,1.8,0,0,1-1.8-1.8V64.4a1.8,1.8,0,0,1,1.8-1.8h0' +
+    'a1.8,1.8,0,0,1,1.8,1.8v9.7h2.3a1.8,1.8,0,0,1,1.6,2.7l-6.4,12' +
+    'a1.8,1.8,0,0,1-1.6,1h0Z' +
+    'M16.9,71.3a1.8,1.8,0,0,1-1.6-2.7l6.7-12' +
+    'a1.8,1.8,0,0,1,1.6-.9,1.9,1.9,0,0,1,1.6.9l1.7,2.8' +
+    'a1.8,1.8,0,1,1-3.1,1.9H23.7l-3.5,6.3,7.1-.5L26.8,66' +
+    'a1.8,1.8,0,0,1,.6-2.5l9.8-6.1a1.8,1.8,0,0,1,1.9,3.1l-8.2,5.1' +
+    'L32,67.6a1.8,1.8,0,0,1-1.4,2.8l-13.5.9H16.9Z' +
+    'M35.8,46.9L35,46.7l-8.7-4.3-1,2a1.8,1.8,0,0,1-3.1.3l-8-11' +
+    'a1.8,1.8,0,0,1,1.4-2.9l13.6-.7' +
+    'a1.8,1.8,0,0,1,1.6.8,1.8,1.8,0,0,1,.1,1.8l-1.6,3' +
+    'a1.8,1.8,0,1,1-3.3-1.7h0.1l-7.1.4,4.2,5.8,0.5-.9' +
+    'a1.8,1.8,0,0,1,2.5-.8l10.4,5.1A1.8,1.8,0,0,1,35.8,46.9Z' +
+    'M60.5,49.9a11.3,11.3,0,1,1-3.3-8A11.2,11.2,0,0,1,60.5,49.9Z'],
+
+    ['m_microwave', 'M63.5,38.9a2.8,2.8,0,0,0-2.1,1H49.6V15.1' +
+    'a1.8,1.8,0,0,0-.5-1.3,1.8,1.8,0,0,0-1.3-.5h0' +
+    'a28.4,28.4,0,0,0-15.7,52V82.5H22.8a1.8,1.8,0,0,0,0,3.7H45' +
+    'a1.8,1.8,0,1,0,0-3.7H35.8V67.4a28.4,28.4,0,0,0,12,2.8h0' +
+    'a1.9,1.9,0,0,0,1.8-1.8V43.6H61.3a2.8,2.8,0,0,0,2.1,1' +
+    'A2.8,2.8,0,1,0,63.5,38.9ZM46,66.4a24.8,24.8,0,0,1,0-49.4V66.4Z' +
+    'M41.7,64H41.2a24.3,24.3,0,0,1-12.9-9.7L28,53.9' +
+    'a1.8,1.8,0,0,1,3.1-2l0.2,0.3a20.3,20.3,0,0,0,10.9,8.2' +
+    'A1.8,1.8,0,0,1,41.7,64Z' +
+    'M66.4,53.1a1.8,1.8,0,0,1-.5-3.6A8.1,8.1,0,0,0,66,34' +
+    'a1.8,1.8,0,0,1,1.1-3.5A11.8,11.8,0,0,1,67,53H66.4Z' +
+    'M66.5,58.2a1.8,1.8,0,0,1-.4-3.6,13.1,13.1,0,0,0,0-25.7,' +
+    '1.8,1.8,0,1,1,.7-3.6,16.8,16.8,0,0,1,0,32.9H66.5Z'],
+
+    ['m_relatedIntents', 'M34.5,73.1A7.5,7.5,0,1,1,42,65.6,7.5,7.5,' +
+    '0,0,1,34.5,73.1Zm0-11.3a3.8,3.8,0,1,0,3.8,3.8' +
+    'A3.8,3.8,0,0,0,34.5,61.8Z' +
+    'M56.7,34.3a1.8,1.8,0,0,1-1.8,1.9H42.6v3.1a3.1,3.1,0,0,1-3,3' +
+    'H36.4V54.5a1.9,1.9,0,0,1-3.7,0V42.3h-3a3.1,3.1,0,0,1-3-3' +
+    'V29.5a3,3,0,0,1,3-3h9.8a3,3,0,0,1,3,3v3H54.8' +
+    'A1.8,1.8,0,0,1,56.7,34.3Z' +
+    'M66,41.8a7.5,7.5,0,1,1,7.5-7.5A7.5,7.5,0,0,1,66,41.8Z' +
+    'm0-11.3a3.8,3.8,0,1,0,3.8,3.8A3.8,3.8,0,0,0,66,30.5Z'],
+
+    ['m_intentTraffic', 'M28.9,77.6H28.5a1.8,1.8,0,0,1-1.4-2.2L39,23.3' +
+    'a1.8,1.8,0,0,1,3.6.8l-12,52.1A1.8,1.8,0,0,1,28.9,77.6Z' +
+    'M71.1,77.6a1.8,1.8,0,0,1-1.8-1.4l-12-52.1a1.8,1.8,0,0,1,3.6-.8' +
+    'l12,52.1a1.8,1.8,0,0,1-1.4,2.2H71.1Z' +
+    'M49.9,26.2A1.8,1.8,0,0,1,48,24.4V23.7a1.8,1.8,0,0,1,3.7,0' +
+    'v0.7A1.8,1.8,0,0,1,49.9,26.2Z' +
+    'M49.9,43.6A1.8,1.8,0,0,1,48,41.8V40.2a1.8,1.8,0,0,1,3.7,0' +
+    'v1.6A1.8,1.8,0,0,1,49.9,43.6Zm0-8.7A1.8,1.8,0,0,1,48,33.1' +
+    'V31.5a1.8,1.8,0,0,1,3.7,0v1.6A1.8,1.8,0,0,1,49.9,34.9Z' +
+    'M49.9,69.8A1.8,1.8,0,0,1,48,67.9V66.3a1.8,1.8,0,0,1,3.7,0' +
+    'v1.6A1.8,1.8,0,0,1,49.9,69.8Zm0-8.7A1.8,1.8,0,0,1,48,59.2' +
+    'V57.6a1.8,1.8,0,0,1,3.7,0v1.6A1.8,1.8,0,0,1,49.9,61.1Zm0-8.7' +
+    'A1.8,1.8,0,0,1,48,50.5V48.9a1.8,1.8,0,0,1,3.7,0v1.6' +
+    'A1.8,1.8,0,0,1,49.9,52.3Z' +
+    'M49.9,77.6A1.8,1.8,0,0,1,48,75.7V75a1.8,1.8,0,0,1,3.7,0v0.7' +
+    'A1.8,1.8,0,0,1,49.9,77.6Z'],
+
+    ['m_firewall', 'M75.3,88.8H65.6a4.9,4.9,0,0,1-4.9-4.9V79.1' +
+    'a4.9,4.9,0,0,1,4.9-4.9h9.7a4.9,4.9,0,0,1,4.9,4.9v4.8' +
+    'A4.9,4.9,0,0,1,75.3,88.8ZM65.6,77.9a1.2,1.2,0,0,0-1.2,1.2v4.8' +
+    'a1.2,1.2,0,0,0,1.2,1.2h9.7a1.2,1.2,0,0,0,1.2-1.2V79.1' +
+    'a1.2,1.2,0,0,0-1.2-1.2H65.6Z' +
+    'M53.9,88.8H24.7a4.9,4.9,0,0,1-4.9-4.9V79.1a4.9,4.9,0,0,1,4.9-4.9' +
+    'H53.9a4.9,4.9,0,0,1,4.9,4.9v4.8A4.9,4.9,0,0,1,53.9,88.8Z' +
+    'M24.7,77.9a1.2,1.2,0,0,0-1.2,1.2v4.8a1.2,1.2,0,0,0,1.2,1.2' +
+    'H53.9a1.2,1.2,0,0,0,1.2-1.2V79.1a1.2,1.2,0,0,0-1.2-1.2H24.7Z' +
+    'M34.4,72.1H24.7a4.9,4.9,0,0,1-4.9-4.9V62.4a4.9,4.9,0,0,1,4.9-4.9' +
+    'h9.7a4.9,4.9,0,0,1,4.9,4.9v4.8A4.9,4.9,0,0,1,34.4,72.1Z' +
+    'M24.7,61.2a1.2,1.2,0,0,0-1.2,1.2v4.8a1.2,1.2,0,0,0,1.2,1.2h9.7' +
+    'a1.2,1.2,0,0,0,1.2-1.2V62.4a1.2,1.2,0,0,0-1.2-1.2H24.7Z' +
+    'M75.3,72.1H46.1a4.9,4.9,0,0,1-4.9-4.9V62.4a4.9,4.9,0,0,1,4.9-4.9' +
+    'H75.3a4.9,4.9,0,0,1,4.9,4.9v4.8A4.9,4.9,0,0,1,75.3,72.1Z' +
+    'M46.1,61.2a1.2,1.2,0,0,0-1.2,1.2v4.8a1.2,1.2,0,0,0,1.2,1.2H75.3' +
+    'a1.2,1.2,0,0,0,1.2-1.2V62.4a1.2,1.2,0,0,0-1.2-1.2H46.1Z' +
+    'M67.7,40.7c-0.2-4.8-3.6-8.8-6.3-12s-3-3.6-3.3-4.8' +
+    'a13.1,13.1,0,0,1,1-9.7,2.2,2.2,0,0,0,.3-1.1,1.9,1.9,0,0,' +
+    '0-.8-1.5,1.8,1.8,0,0,0-1.7-.2c-0.3.1-8.1,3-10.4,14.7-1.4-2.3' +
+    '-3.4-4.6-5.9-5.4a1.8,1.8,0,0,0-2,.6,1.9,1.9,0,0,0-.2,2.1,6.8,6.8,' +
+    '0,0,1-.6,7.1c-1.4,1.8-5.9,8.3-4.1,14.9,1.2,4.1,4.6,7.3,10.2,9.4' +
+    'h1.6l0.2-.2h0.1l0.2-.3,0.2-.3h0V53.2a1.6,1.6,0,0,0,0-.4,1.7,1.7,' +
+    '0,0,0,0-.3h0V52.2h0V51.8L46,51.6H45.9c-0.3-.4-2.4-3-2.1-5.9' +
+    'a5,5,0,0,1,.7-2.1c1,2,2.7,4.4,5.5,4.6a5.1,5.1,0,0,0,3.9-1.3' +
+    'A8.2,8.2,0,0,0,56,43.5a7.3,7.3,0,0,1,.3,2.6,7.6,7.6,0,0,' +
+    '1-3.1,5.3,1.8,1.8,0,0,0,1.2,3.3h0c0.3,0,6.3-.1,10.1-4.3' +
+    'C66.9,47.9,67.9,44.6,67.7,40.7Zm-5.8,7.1a9,9,0,0,1-2.7,2,9.9,9.9,' +
+    '0,0,0,.9-3.5c0.3-5.1-3.4-9.2-3.5-9.4a1.8,1.8,0,0,0-3.2,1.2' +
+    'c0,1.4-.5,4.8-1.8,5.9a1.4,1.4,0,0,1-1.2.4c-1.7-.1-2.9-3.3-3.3-4.8' +
+    'a1.8,1.8,0,0,0-1.2-1.4,1.8,1.8,0,0,0-1.8.3,9.7,9.7,0,0,' +
+    '0-4,6.8,9.4,9.4,0,0,0,.3,3.1,8.4,8.4,0,0,1-3.1-4.4' +
+    'c-1.4-5,2.6-10.5,3.5-11.7A10,10,0,0,0,42.8,27,27.2,27.2,0,0,' +
+    '1,46,33.7a1.8,1.8,0,0,0,3.6-.6,33.2,33.2,0,0,1,.4-5.4,19.3,19.3,' +
+    '0,0,1,4-9.7,19.1,19.1,0,0,0,.5,6.7c0.5,2.1,2.2,4,4.1,6.3' +
+    's5.3,6.2,5.5,9.8A9.1,9.1,0,0,1,61.9,47.8Z'],
+
+    ['m_balancer', 'M33.4,56.6H26.7a3.1,3.1,0,0,1-3-3V46.9a3.1,3.1,0,0,1,3-3' +
+    'h6.7a3.1,3.1,0,0,1,3,3v6.7A3.1,3.1,0,0,1,33.4,56.6Z' +
+    'M73.3,36.5H66.6a3.1,3.1,0,0,1-3-3V26.7a3.1,3.1,0,0,1,3-3' +
+    'h6.7a3.1,3.1,0,0,1,3,3v6.7A3.1,3.1,0,0,1,73.3,36.5Z' +
+    'M73.3,56.1H66.6a3.1,3.1,0,0,1-3-3V46.4a3.1,3.1,0,0,1,3-3' +
+    'h6.7a3.1,3.1,0,0,1,3,3v6.7A3.1,3.1,0,0,1,73.3,56.1Z' +
+    'M73.3,76.3H66.6a3.1,3.1,0,0,1-3-3V66.6a3.1,3.1,0,0,1,3-3' +
+    'h6.7a3.1,3.1,0,0,1,3,3v6.7A3.1,3.1,0,0,1,73.3,76.3Z' +
+    'M62.7,70.4a1.9,1.9,0,0,1-1.8,1.5H60.5a15.2,15.2,0,0,1-10.9-9.1' +
+    'c-3.9-8.6-4.7-9.8-10.8-10.4a1.8,1.8,0,0,1-1.6-1.7,0.3,0.3,0,0,1,0-.1' +
+    'h0V50.1h0a1.8,1.8,0,0,1,1.7-2c6.2-.5,7-1.7,10.9-10.4' +
+    'a15.2,15.2,0,0,1,10.7-9.1,1.8,1.8,0,1,1,.8,3.6,11.5,11.5,0,0,0-8.2,7' +
+    'c-2,4.4-3.4,7.3-5.3,9.2H60.8a1.8,1.8,0,1,1,0,3.7h-13' +
+    'c1.8,1.9,3.2,4.8,5.2,9.1a11.5,11.5,0,0,0,8.3,7' +
+    'A1.9,1.9,0,0,1,62.7,70.4Z'],
+
+    ['m_ips', 'M79.4,26.8a0.9,0.9,0,0,0-.1-0.3V26.1l-0.3-.4-0.2-.2' +
+    'H78.6c-1.3-1-11-8-28.3-8H49.7c-18.7,0-28.1,7.8-28.5,8.1' +
+    'a2,2,0,0,0-.7,1.3c-1.1,22.8,6.7,36.8,13.4,44.4S48.3,82.4,49.1,82.7' +
+    'h1.6c0.3-.1,7.9-3.1,15.3-11.4S80.5,49.7,79.4,26.8ZM50,79' +
+    'c-3.9-1.7-27.3-13.4-25.8-51.1,2.3-1.6,10.7-6.8,25.5-6.8h0.5' +
+    'c14.4,0,23.2,5.2,25.5,6.8C77.2,65.6,53.9,77.3,50,79Z' +
+    'M41.7,41.9a1.8,1.8,0,0,1-1.8-1.9V37.3a9.8,9.8,0,0,1,9.8-9.8h0.6' +
+    'a9.8,9.8,0,0,1,9.8,9.8v2.6a1.8,1.8,0,1,1-3.7,0V37.3' +
+    'a6.1,6.1,0,0,0-6.1-6.1H49.6a6.1,6.1,0,0,0-6.1,6.1v2.8' +
+    'A1.8,1.8,0,0,1,41.7,41.9Z' +
+    'M58.6,63.1H41.3a3.7,3.7,0,0,1-3.6-3.7V47.3a3.7,3.7,0,0,1,3.6-3.7' +
+    'H58.6a3.8,3.8,0,0,1,3.6,3.7V59.4A3.7,3.7,0,0,1,58.6,63.1Z'],
+
+    ['m_ids', 'M69.7,41.5c-2.9,3.6-9.1,5-18.6,4.2a18.4,18.4,0,0,0-8.9,1.4' +
+    'H41.5a1.8,1.8,0,0,1-.7-3.5A22.2,22.2,0,0,1,51.5,42' +
+    'c7.4,0.6,12.5-.2,14.8-2.3L63.2,22.6c-5,2.9-12.5,2.4-15.9,1.9' +
+    'a18.7,18.7,0,0,0-12.7,3.4H34.3l9.5,52.4a1.9,1.9,0,0,1-1.5,2.1' +
+    'H42a1.8,1.8,0,0,1-1.8-1.5L29.9,24.3a1.8,1.8,0,1,1,3.6-.6v0.4' +
+    'a22.3,22.3,0,0,1,14.1-3.2C55,21.8,60.9,20.7,63,18' +
+    'a1.8,1.8,0,0,1,1.9-.6,1.8,1.8,0,0,1,1.4,1.5L70.1,40' +
+    'A1.9,1.9,0,0,1,69.7,41.5Z'],
+
+    ['m_olt', 'M83,47.6H64.5a1.8,1.8,0,0,0-1.9,1.9V74.3' +
+    'a1.8,1.8,0,0,0,1.9,1.8H83a1.8,1.8,0,0,0,1.8-1.8V49.5' +
+    'A1.8,1.8,0,0,0,83,47.6ZM81.1,72.5H77.7v-5a1.4,1.4,0,0,0-1.4-1.4' +
+    'H72.1a1.4,1.4,0,0,0-1.4,1.4v5H66.3V51.3H81.1V72.5Z' +
+    'M70.9,56.9H69.5a1.8,1.8,0,0,1,0-3.7h1.3A1.8,1.8,0,1,1,70.9,56.9Z' +
+    'M77.5,56.9H76.1a1.8,1.8,0,0,1,0-3.7h1.3A1.8,1.8,0,1,1,77.5,56.9Z' +
+    'M70.9,62.5H69.5a1.8,1.8,0,0,1,0-3.7h1.3A1.8,1.8,0,1,1,70.9,62.5Z' +
+    'M77.5,62.5H76.1a1.8,1.8,0,0,1,0-3.7h1.3A1.8,1.8,0,1,1,77.5,62.5Z' +
+    'M40.9,56.2H36.1a1.8,1.8,0,1,1,0-3.7h4.8A1.8,1.8,0,0,1,40.9,56.2Z' +
+    'M82.2,25.7V43.9a1.8,1.8,0,0,1-3.7,0V27.5H32.3V59.8H58.4' +
+    'a1.8,1.8,0,0,1,0,3.7h-28a1.9,1.9,0,0,1-1.8-1.9V45.5H17' +
+    'a1.8,1.8,0,0,1,0-3.7H28.6V25.7a1.8,1.8,0,0,1,1.8-1.8h50' +
+    'A1.8,1.8,0,0,1,82.2,25.7Z'],
+
+    ['m_onu', 'M39.8,58.7H35a1.8,1.8,0,1,1,0-3.7h4.9' +
+    'A1.8,1.8,0,1,1,39.8,58.7Z' +
+    'M81.4,28.3V46.5a1.9,1.9,0,0,1-3.7,0V30.2H31.2V62.4H57.4' +
+    'a1.8,1.8,0,1,1,0,3.7H29.3a1.8,1.8,0,0,1-1.8-1.9V48.1H15.9' +
+    'a1.8,1.8,0,1,1,0-3.7H27.5V28.3a1.8,1.8,0,0,1,1.8-1.8H79.5' +
+    'A1.8,1.8,0,0,1,81.4,28.3Z' +
+    'M85.8,60.3L75.1,49.6a1.8,1.8,0,0,0-2.6,0L61.6,60.3' +
+    'a1.8,1.8,0,0,0,0,2.6,1.8,1.8,0,0,0,2.6,0l0.2-.2v8.8' +
+    'a1.8,1.8,0,0,0,1.8,1.8H81.2a1.8,1.8,0,0,0,1.8-1.8V62.7l0.2,0.2' +
+    'A1.8,1.8,0,0,0,85.8,60.3Zm-6.5,9.4H68.1V59.1l5.6-5.6L79.4,59V69.7Z'],
+
+    ['m_swap', 'M62.2,54.7l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V47.1' +
+    'a1.8,1.8,0,1,1,3.7,0v2.6l10.8-6L64,38v2.6a1.8,1.8,0,0,1-1.8,1.8' +
+    'H47.1a1.8,1.8,0,0,1,0-3.7H60.3V34.9a1.8,1.8,0,0,1,2.7-1.6' +
+    'l16.5,8.8a1.8,1.8,0,0,1,0,3.2L63.1,54.5Z' +
+        'M37.4,66.6l-0.9-.2L20,57.2a1.8,1.8,0,0,1,0-3.2l16.5-8.8' +
+    'a1.8,1.8,0,0,1,2.7,1.6v3.8H52.5a1.8,1.8,0,0,1,0,3.7H37.4' +
+    'a1.8,1.8,0,0,1-1.8-1.8V49.9L24.8,55.7l10.8,6V59' +
+    'a1.8,1.8,0,1,1,3.7,0v5.7a1.8,1.8,0,0,1-.9,1.6Z'],
+
+    ['m_shortestGeoPath', 'M49.7,17.5A32.3,32.3,0,1,0,81.9,49.8,32.3,32.3,0,' +
+    '0,0,49.7,17.5Zm0,60.9A28.6,28.6,0,1,1,78.2,49.8,28.6,28.6,0,0,1,' +
+    '49.7,78.4Z M60.9,49a1.5,1.5,0,0,1-.1-0.4,0.8,0.8,0,0,1,0-.3' +
+    'C60.9,48.5,60.9,48.8,60.9,49Z' +
+    'M75.4,48.6a1.8,1.8,0,0,1-1.8,1.8h-9' +
+    'a38.2,38.2,0,0,1-8.3,22.8,1.8,1.8,0,0,1-1.4.7,1.8,1.8,0,0,' +
+    '1-1.1-.4,1.8,1.8,0,0,1-.3-2.6,34.6,34.6,0,0,0,7.5-21.6V49' +
+    'c0-.3,0-0.5,0-0.7a0.1,0.1,0,0,1,0-.1,33.2,33.2,0,0,0-.7-6.1H60' +
+    'a5.1,5.1,0,0,1-3.1-9.1A33,33,0,0,0,52.9,27' +
+    'a1.8,1.8,0,1,1,2.8-2.4,36.2,36.2,0,0,1,4.7,7.2,5.1,5.1,0,0,' +
+    '1,3.1,8.7,38.3,38.3,0,0,1,.9,6.2h9.1A1.8,1.8,0,0,1,75.4,48.6Z' +
+    'M46.5,71a1.8,1.8,0,0,1-1.4,3,1.8,1.8,0,0,1-1.4-.7,36.3,36.3,' +
+    '0,0,1-4.3-6.7H39a5.1,5.1,0,0,1-2.9-9.3,40.3,40.3,0,0,1-.8-6.9H26' +
+    'a1.8,1.8,0,0,1,0-3.7h9.3a38,38,0,0,1,8.3-21.5,1.8,1.8,0,1,1,2.8,' +
+    '2.3,34.5,34.5,0,0,0-7.6,21.8,36,36,0,0,0,.7,7.2,5.1,5.1,0,0,' +
+    '1,4.5,5.1,5,5,0,0,1-1.4,3.5A33.4,33.4,0,0,0,46.5,71Z' +
+    'M44.9,56.9a1.8,1.8,0,0,1-1.1-.4,1.8,1.8,0,0,1-.3-2.6l0.6-.8' +
+    'A1.8,1.8,0,1,1,47,55.3l-0.6.8A1.8,1.8,0,0,1,44.9,56.9Zm3.9-5' +
+    'a1.8,1.8,0,0,1-1.1-.4,1.8,1.8,0,0,1-.3-2.6l0.6-.8' +
+    'a1.8,1.8,0,1,1,2.9,2.3l-0.6.8A1.8,1.8,0,0,1,48.8,51.9Zm3.9-5' +
+    'a1.8,1.8,0,0,1-1.1-.4,1.8,1.8,0,0,1-.3-2.6l0.6-.8' +
+    'a1.8,1.8,0,1,1,2.9,2.3l-0.6.8A1.8,1.8,0,0,1,52.7,46.9Z'],
+
+    ['m_source', 'M71,63.8l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V57.1' +
+    'a1.8,1.8,0,0,1,3.7,0v1.7l8.2-4.5-8.2-4.4v1.7A1.8,1.8,0,0,1,71,53.4' +
+    'H58.2a1.8,1.8,0,0,1,0-3.7H69.2V46.8a1.8,1.8,0,0,1,2.7-1.6l14,7.5' +
+    'a1.8,1.8,0,0,1,0,3.2l-14,7.7Z' +
+    'M32.7,77.7a3.6,3.6,0,0,1-3.1-1.8L16.1,52.1l-0.9-1.6' +
+    'a19.3,19.3,0,0,1-2.1-8.7,19.6,19.6,0,0,1,6.1-14.2' +
+    'A19.5,19.5,0,0,1,52.1,40.5h0a19.5,19.5,0,0,1-2,9.9l-1,1.8' +
+    'L35.8,75.9A3.6,3.6,0,0,1,32.7,77.7Zm0-51.7' +
+    'A15.8,15.8,0,0,0,18.5,48.8l0.8,1.4L32.7,73.9,46,50.3l0.8-1.4' +
+    'a15.9,15.9,0,0,0,1.6-8.1h0A15.8,15.8,0,0,0,33.6,26h-1Z' +
+    'm0,21.1A8.2,8.2,0,1,1,40.8,39,8.2,8.2,0,0,1,32.7,47.1Z' +
+    'm0-12.6A4.5,4.5,0,1,0,37.1,39,4.5,4.5,0,0,0,32.7,34.5Z'],
+
+    ['m_destination', 'M30.3,63.8l-0.9-.3a1.8,1.8,0,0,1-.9-1.6V57.1' +
+    'a1.8,1.8,0,0,1,3.7,0v1.7l8.2-4.5-8.2-4.4v1.7a1.8,1.8,0,0,1-1.8,1.8' +
+    'H17.5a1.8,1.8,0,1,1,0-3.7H28.4V46.8a1.8,1.8,0,0,1,2.7-1.6l14,7.5' +
+    'a1.8,1.8,0,0,1,0,3.2l-14,7.7Z' +
+    'M64.9,77.7a3.6,3.6,0,0,1-3.1-1.8L48.3,52.1l-0.9-1.6' +
+    'a19.3,19.3,0,0,1-2-8.6,19.6,19.6,0,0,1,6.1-14.2' +
+    'A19.5,19.5,0,0,1,84.3,40.5a19.5,19.5,0,0,1-1.9,9.8v0.2l-0.9,1.7' +
+    'L68,75.9A3.6,3.6,0,0,1,64.9,77.7ZM50.7,48.8l0.8,1.4' +
+    'L64.9,73.9,78.2,50.3,79,48.8h0a15.8,15.8,0,0,0,1.6-8' +
+    'a15.8,15.8,0,1,0-29.9,8h0Zm14.1-1.7' +
+    'A8.2,8.2,0,1,1,73,39,8.2,8.2,0,0,1,64.9,47.1Z' +
+    'm0-12.6A4.5,4.5,0,1,0,69.3,39,4.5,4.5,0,0,0,64.9,34.5Z'],
+
+    ['m_topo', 'M31.3,73H21.5a3.1,3.1,0,0,1-3-3V60.1a3.1,3.1,0,0,1,3-3' +
+    'h9.8a3.2,3.2,0,0,1,3,3V70A3.1,3.1,0,0,1,31.3,73Z' +
+    'M78.5,46.7H68.7a3.1,3.1,0,0,1-3-3V33.8a3.1,3.1,0,0,1,3-3h9.8' +
+    'a3.1,3.1,0,0,1,3,3v9.8A3.1,3.1,0,0,1,78.5,46.7Z' +
+    'M40.8,42.9H31a3.1,3.1,0,0,1-3-3V30a3.1,3.1,0,0,1,3-3' +
+    'h9.9a2.9,2.9,0,0,1,2.9,3v9.8A3.1,3.1,0,0,1,40.8,42.9Z' +
+    'M37.4,66.1a1.8,1.8,0,0,1-1.2-3.3L61.1,42a1.8,1.8,0,1,1,2.4,2.8' +
+    'L38.6,65.7A1.8,1.8,0,0,1,37.4,66.1Z' +
+    'M27.4,55.5a1.8,1.8,0,0,1-1.5-3l5.8-7.7a1.8,1.8,0,1,1,2.9,2.2' +
+    'l-5.8,7.7A1.8,1.8,0,0,1,27.4,55.5Z' +
+    'M62.5,39.7H62.2L46.6,36.5a1.8,1.8,0,1,1,.7-3.6L62.9,36' +
+    'A1.8,1.8,0,0,1,62.5,39.7Z'],
+
+    ['m_shortestPath', 'M28.2,31.2H19.5a3,3,0,0,1-3-3V19.5a3,3,0,0,1,3-3' +
+    'h8.6c1.8,0.4,3,1.4,3,3v8.6A3,3,0,0,1,28.2,31.2Z' +
+    'M80.2,83.2H71.6a3,3,0,0,1-3-3V71.5a3,3,0,0,1,3-3h8.6' +
+    'c1.7,0.4,3,1.4,3,3v8.6A3,3,0,0,1,80.2,83.2Z' +
+    'M67.6,67.4a1.8,1.8,0,0,1-1.3.5,1.9,1.9,0,0,1-1.3-.5L54.7,57.1' +
+    'H45.6a3,3,0,0,1-3-3V45.5a2.1,2.1,0,0,1,.1-0.5L32.3,34.7' +
+    'a1.8,1.8,0,0,1,0-2.6,1.9,1.9,0,0,1,2.6,0L45.3,42.5h8.9' +
+    'a3,3,0,0,1,3,3v8.6a0.9,0.9,0,0,1,0,.2L67.6,64.8' +
+    'A1.8,1.8,0,0,1,67.6,67.4Z'],
+
+    ['m_disjointPaths', 'M67.7,59.8h9.4a2.9,2.9,0,0,1,3,3v9.4' +
+    'a3.1,3.1,0,0,1-3,3H67.7a3.1,3.1,0,0,1-3-3V62.9' +
+    'A3.1,3.1,0,0,1,67.7,59.8Z' +
+    'M22.9,59.8h9.4a2.9,2.9,0,0,1,3,3v9.4a3.1,3.1,0,0,1-3,3H22.9' +
+    'a3.1,3.1,0,0,1-3-3V62.9A3.1,3.1,0,0,1,22.9,59.8Z' +
+    'M45.3,24.7h9.4a2.9,2.9,0,0,1,3,3v9.4a3.1,3.1,0,0,1-3,3H45.3' +
+    'a3.1,3.1,0,0,1-3-3V27.7A3.1,3.1,0,0,1,45.3,24.7Z' +
+    'M65.9,58.5a1.8,1.8,0,0,1-1.5-.8L55.3,44.3a1.8,1.8,0,0,1,3.1-2.1' +
+    'l9.1,13.4A1.8,1.8,0,0,1,65.9,58.5Z' +
+    'M61.1,68.8H39.1a1.8,1.8,0,1,1,0-3.7H61.1A1.8,1.8,0,0,1,61.1,68.8Z' +
+    'M35.5,59.9l-1-.3a1.8,1.8,0,0,1-.6-2.5l8.8-14.3' +
+    'a1.8,1.8,0,0,1,3.1,1.9L37.1,59A1.8,1.8,0,0,1,35.5,59.9Z'],
+
+    ['m_region', 'M49.8,70.9a3.4,3.4,0,0,1-3-1.8L34.3,47l-0.8-1.5' +
+    'a18.2,18.2,0,0,1-1.9-8.2,18.4,18.4,0,0,1,5.8-13.3' +
+    'A18.3,18.3,0,0,1,68.1,36.1h0a18.4,18.4,0,0,1-1.9,9.3' +
+    'L65.3,47,52.8,69.2A3.4,3.4,0,0,1,49.8,70.9Zm0-48.3' +
+    'A14.6,14.6,0,0,0,36.7,43.8l0.7,1.3L49.8,67,62.2,45.2l0.8-1.3' +
+    'a14.7,14.7,0,0,0,1.5-7.5h0A14.8,14.8,0,0,0,50.7,22.7H49.8Z' +
+    'm0,19.7a7.7,7.7,0,1,1,7.7-7.7A7.7,7.7,0,0,1,49.8,42.4Zm0-11.8' +
+    'a4.1,4.1,0,1,0,4.1,4.1A4.1,4.1,0,0,0,49.8,30.6Z' +
+    'M81.7,80.8H17.9a1.8,1.8,0,0,1-1.6-2.7l9.2-16.8' +
+    'a1.8,1.8,0,0,1,1.6-1h9.5a1.8,1.8,0,1,1,0,3.7H28.2L21,77.1H78.6' +
+    'L71.4,64H61.9a1.8,1.8,0,1,1,0-3.7H72.5a1.8,1.8,0,0,1,1.6,1' +
+    'l9.2,16.8A1.8,1.8,0,0,1,81.7,80.8Z'],
+]);
+
+export const extraGlyphs = new Map<string, string>([
+        ['_yang', '0 0 400 400'],
+        ['yang', 'M323.3,199.2a33.2,33.2,0,1,1-66.4,0' +
+        'c0-18.4,14.9-34.1,33.2-33.3S323.3,180.8,323.3,199.2Z' +
+        'M286.5,289.9c-78.2-.3-86.6-72.2-86.9-89.1s-14.6-91.8-88.3-88.3' +
+        'c-7.5.3-34.6,1.2-56.9,20.1-25.8,21.8-29,53.9-30.5,68.2-0.2,' +
+        '2.2-.4,4.4-0.5,6.5h0a175.5,175.5,0,0,0,171,172.9H199' +
+        'a175.5,175.5,0,0,0,58.6-10l3.9-1.4,3.9-1.5,3.9-1.7h0' +
+        'l3.9-1.7,2.8-1.3,2.7-1.4a175.6,175.6,0,0,0,95.9-155.1' +
+        'C372.4,226.7,358,290.1,286.5,289.9ZM110.1,237.7' +
+        'A33.6,33.6,0,1,1,143.7,204,33.6,33.6,0,0,1,110.1,237.7Z'],
+]);
+
+
+/**
+ * ONOS GUI -- SVG -- Glyph Data Service
+ */
+@Injectable()
+export class GlyphDataService {
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('GlyphDataService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts b/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts
new file mode 100644
index 0000000..95699d0
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive, ElementRef, Input, OnInit } from '@angular/core';
+import { IconService } from './icon.service';
+import { LogService } from '../../log.service';
+import * as d3 from 'd3';
+
+/**
+ * ONOS GUI -- SVG -- Icon Directive
+ *
+ * TODO: Deprecated - this directive may be removed altogether as it has been
+ * rebuilt as IconComponent instead
+ */
+@Directive({
+  selector: '[onosIcon]'
+})
+export class IconDirective implements OnInit {
+    @Input() iconId: string;
+    @Input() iconSize: number = 20;
+
+    constructor(
+        private el: ElementRef,
+        private is: IconService,
+        private log: LogService
+    ) {
+        // Note: iconId is not available until initialization
+        this.log.debug('IconDirective constructed');
+    }
+
+    ngOnInit() {
+        const div = d3.select(this.el.nativeElement);
+        div.selectAll('*').remove();
+        this.is.loadEmbeddedIcon(div, this.iconId, this.iconSize);
+        this.log.debug('IconDirective initialized:', this.iconId);
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
new file mode 100644
index 0000000..8d9d3c6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { GlyphService } from './glyph.service';
+import { LogService } from '../../log.service';
+import { SvgUtilService } from './svgutil.service';
+import * as d3 from 'd3';
+
+const vboxSize = 50;
+const cornerSize = vboxSize / 10;
+const viewBox = '0 0 ' + vboxSize + ' ' + vboxSize;
+
+export const glyphMapping = new Map<string, string>([
+    // Maps icon ID to the glyph ID it uses.
+    // NOTE: icon ID maps to a CSS class for styling that icon
+    ['active', 'checkMark'],
+    ['inactive','xMark'],
+
+    ['plus','plus'],
+    ['minus','minus'],
+    ['play','play'],
+    ['stop','stop'],
+
+    ['upload','upload'],
+    ['download','download'],
+    ['delta','delta'],
+    ['nonzero','nonzero'],
+    ['close','xClose'],
+
+    ['topo','topo'],
+
+    ['refresh','refresh'],
+    ['query','query'],
+    ['garbage','garbage'],
+
+
+    ['upArrow','triangleUp'],
+    ['downArrow','triangleDown'],
+
+    ['appInactive','unknown'],
+
+    ['node','node'],
+    ['devIcon_SWITCH','switch'],
+    ['devIcon_ROADM','roadm'],
+    ['devIcon_OTN','otn'],
+
+    ['portIcon_DEFAULT','m_ports'],
+
+    ['meter','meterTable'], // TODO: m_meter icon?
+
+    ['deviceTable','switch'],
+    ['flowTable','flowTable'],
+    ['portTable','portTable'],
+    ['groupTable','groupTable'],
+    ['meterTable','meterTable'],
+    ['pipeconfTable','pipeconfTable'],
+
+    ['hostIcon_endstation','endstation'],
+    ['hostIcon_router','router'],
+    ['hostIcon_bgpSpeaker','bgpSpeaker'],
+
+    // navigation menu icons...
+    ['nav_apps','bird'],
+    ['nav_settings','cog'],
+    ['nav_cluster','node'],
+    ['nav_processors','allTraffic'],
+
+    ['nav_topo','topo'],
+    ['nav_topo2','m_cloud'],
+    ['nav_devs','switch'],
+    ['nav_links','ports'],
+    ['nav_hosts','endstation'],
+    ['nav_intents','relatedIntents'],
+    ['nav_tunnels','ports'], // TODO: use tunnel glyph, when available
+    ['nav_yang','yang'],
+]);
+
+/**
+ * ONOS GUI -- SVG -- Icon Service
+ */
+@Injectable()
+export class IconService {
+
+    constructor(
+        private gs: GlyphService,
+        private log: LogService,
+        private sus: SvgUtilService
+    ) {
+
+        this.log.debug('IconService constructed');
+    }
+
+    ensureIconLibDefs() {
+        let body = d3.select('body');
+        let svg = body.select('svg#IconLibDefs');
+        if (svg.empty()) {
+            svg = body.append('svg').attr('id', 'IconLibDefs');
+            svg.append('defs');
+        }
+        return svg.select('defs');
+    }
+
+    /**
+     * Load an icon
+     *
+     * @param div A D3 selection of the '&lt;div&gt;' element into which icon should load
+     * @param glyphId Identifies the glyph to use
+     * @param size The dimension of icon in pixels. Defaults to 20.
+     * @param installGlyph If truthy, will cause the glyph to be added to
+     *      well-known defs element. Defaults to false.
+     * @param svgClass The CSS class used to identify the SVG layer.
+     *      Defaults to 'embeddedIcon'.
+     */
+    loadIcon(div, glyphId: string = 'unknown', size: number = 20, installGlyph: boolean = true, svgClass: string = 'embeddedIcon') {
+        let dim = size || 20;
+        let svgCls = svgClass || 'embeddedIcon';
+        let gid = glyphId || 'unknown';
+        let g;
+        let svgIcon: any;
+
+        if (installGlyph) {
+            this.gs.loadDefs(this.ensureIconLibDefs(), [gid], true);
+        }
+        this.log.warn('loadEmbeddedIcon. install done');
+
+        svgIcon = div
+            .append('svg')
+            .attr('class', svgCls)
+            .attr('width', dim)
+            .attr('height', dim)
+            .attr('viewBox', viewBox);
+
+        g = svgIcon.append('g')
+            .attr('class', 'icon');
+
+        g.append('rect')
+            .attr('width', vboxSize)
+            .attr('height', vboxSize)
+            .attr('rx', cornerSize);
+
+        g.append('use')
+            .attr('width', vboxSize)
+            .attr('height', vboxSize)
+            .attr('class', 'glyph')
+            .attr('xlink:href', '#' + gid);
+    }
+
+    /**
+     * Load an icon by class.
+     * @param div A D3 selection of the <DIV> element into which icon should load
+     * @param iconCls The CSS class used to identify the icon
+     * @param {number} size The dimension of icon in pixels. Defaults to 20.
+     * @param {boolean} installGlyph If truthy, will cause the glyph to be added to
+     *      well-known defs element. Defaults to false.
+     * @param svgClass The CSS class used to identify the SVG layer.
+     *      Defaults to 'embeddedIcon'.
+     */
+    loadIconByClass(div, iconCls: string, size: number, installGlyph: boolean, svgClass='embeddedIcon') {
+        this.loadIcon(div, glyphMapping.get(iconCls), size, installGlyph, svgClass);
+        div.select('svg g').classed(iconCls, true);
+    }
+
+    /**
+     * Load an embedded icon.
+     */
+    loadEmbeddedIcon(div, iconCls: string, size: number) {
+        this.loadIconByClass(div, iconCls, size, true);
+    }
+
+    /**
+     * Load an icon only to the svg defs collection
+     *
+     * Note: This is added for use with IconComponent, where the icon's
+     * svg element is defined in the component template (and not built
+     * inline using d3 manipulation
+     *
+     * @param iconCls The icon class as a string
+     */
+    loadIconDef(iconCls: string): void {
+        this.gs.loadDefs(this.ensureIconLibDefs(), [glyphMapping.get(iconCls)], true);
+        this.log.debug('icon defintion', iconCls, 'added to defs');
+    }
+
+
+    /**
+     * Add a device icon
+     *
+     * Adds a device glyph to the specified element.
+     * Returns the D3 selection of the glyph (use) element.
+     */
+    addDeviceIcon(elem, glyphId, iconDim) {
+        let gid = this.gs.glyphDefined(glyphId) ? glyphId : 'query';
+        return elem.append('use').attr({
+            'xlink:href': '#' + gid,
+            width: iconDim,
+            height: iconDim,
+        });
+    }
+
+    addHostIcon(elem, radius, glyphId) {
+        let dim = radius * 1.5;
+        let xlate = -dim / 2;
+        let g = elem.append('g')
+                .attr('class', 'svgIcon hostIcon');
+
+        g.append('circle').attr('r', radius);
+
+        g.append('use').attr({
+            'xlink:href': '#' + glyphId,
+            width: dim,
+            height: dim,
+            transform: this.sus.translate(xlate, xlate),
+        });
+        return g;
+    }
+
+    registerIconMapping(iconId, glyphId) {
+        if (glyphMapping[iconId]) {
+            this.log.warn('Icon with id', iconId, 'already mapped. Ignoring.');
+        } else {
+            // map icon-->glyph
+            glyphMapping[iconId] = glyphId;
+            // make sure definition is installed
+            this.gs.loadDefs(this.ensureIconLibDefs(), [glyphId], true);
+        }
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/glyph-theme.css b/web/gui2/src/main/webapp/app/fw/svg/icon/glyph-theme.css
new file mode 100644
index 0000000..c657ae6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/glyph-theme.css
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Glyph Service (theme) -- CSS file
+ */
+
+.light svg .glyph,
+.dark svg .glyph.overlay {
+    fill: blue;
+}
+
+/*
+* NOTE: Keeping the theme black while we
+* wait for the mockup theme designs to be made
+*/
+.dark svg .glyph,
+.light svg .glyph.overlay {
+    fill: blue;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/glyph.css b/web/gui2/src/main/webapp/app/fw/svg/icon/glyph.css
new file mode 100644
index 0000000..9a65ddc
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/glyph.css
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Glyph Service (layout) -- CSS file
+ */
+
+svg .glyph {
+    stroke: none;
+    fill-rule: evenodd;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.css b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.css
new file mode 100644
index 0000000..347837a
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.css
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Icon Service (layout) -- CSS file
+ */
+
+svg#IconLibDefs {
+  display: none;
+}
+
+svg .svgIcon {
+    fill-rule: evenodd;
+}
+
+svg.embeddedIcon g.icon {
+    fill: none;
+}
+
+svg.embeddedIcon g.icon rect {
+    stroke: none;
+    fill: none;
+}
+
+svg.embeddedIcon g.icon .glyph {
+    stroke: none;
+    fill-rule: evenodd;
+}
+
+svg.embeddedIcon .icon.appInactive .glyph {
+    fill: none !important;
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.html b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.html
new file mode 100644
index 0000000..6a32d87
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.html
@@ -0,0 +1,21 @@
+<!--
+~ Copyright 2014-present Open Networking Foundation
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~     http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<svg class="embeddedIcon" [attr.width]="iconSize" [attr.height]="iconSize" viewBox="0 0 50 50">
+    <g class="icon" [ngClass]="iconId">
+        <rect width="50" height="50" rx="5"></rect>
+        <use width="50" height="50" class="glyph" [attr.href]="iconTag()"></use>
+    </g>
+</svg>
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts
new file mode 100644
index 0000000..99b94d2
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit, Input } from '@angular/core';
+import { IconService, glyphMapping } from '../icon.service';
+import { LogService } from '../../../log.service';
+import * as d3 from 'd3';
+
+/**
+ * Icon Component
+ *
+ * Note: This is an alternative to the Icon Directive from ONOS 1.0.0
+ * It has been implemented as a Component because it was inadvertently adding
+ * in a template through d3 DOM manipulations - it's better to make it a Comp
+ * and build a template the Angular 6 way
+ *
+ * Remember: The CSS files applied here only apply to this component
+ */
+@Component({
+  selector: 'onos-icon',
+  templateUrl: './icon.component.html',
+  styleUrls: ['./icon.component.css', './icon.theme.css', './glyph.css', './glyph-theme.css']
+})
+export class IconComponent implements OnInit {
+    @Input() iconId: string;
+    @Input() iconSize: number = 20;
+
+    constructor(
+        private is: IconService,
+        private log: LogService
+    ) {
+        // Note: iconId is not available until initialization
+        this.log.debug('IconComponent constructed');
+    }
+
+    ngOnInit() {
+        this.is.loadIconDef(this.iconId);
+        this.log.debug('IconComponent initialized for ', this.iconId);
+    }
+
+    /**
+     * Get the corresponding iconTag from the glyphMapping in the iconService
+     * @returns The iconTag corresponding to the iconId of this instance
+     */
+    iconTag(): string {
+        return '#' + glyphMapping.get(this.iconId);
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.theme.css b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.theme.css
new file mode 100644
index 0000000..59cf10f
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.theme.css
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Icon Service (theme) -- CSS file
+ */
+
+.light div.close-btn svg.embeddedIcon g.icon .glyph {
+    fill: #333333;
+}
+
+/* Sortable table headers */
+.light div.tableColSort svg.embeddedIcon .icon .glyph {
+    fill: #353333;
+}
+
+/* active / inactive (check/xmark) icons */
+.light svg.embeddedIcon .icon.active .glyph {
+    fill: #04bf34;
+}
+
+.light svg.embeddedIcon .icon.inactive .glyph {
+    fill: #c0242b;
+}
+
+.light table svg.embeddedIcon .icon .glyph {
+    fill: #3c3a3a;
+}
+
+/* ========== DARK Theme ========== */
+
+.dark div.close-btn svg.embeddedIcon g.icon .glyph {
+    fill: #8d8d8d;
+}
+
+.dark div.tableColSort svg.embeddedIcon .icon .glyph {
+    fill: #888888;
+}
+
+.dark svg.embeddedIcon .icon.active .glyph {
+    fill: #04bf34;
+}
+
+.dark svg.embeddedIcon .icon.inactive .glyph {
+    fill: #c0242b;
+}
+
+.dark table svg.embeddedIcon .icon .glyph {
+    fill: #9999aa;
+}
+
+svg.embeddedIcon g.icon .glyph {
+    fill: #007dc4;
+}
+
+svg.embeddedIcon:hover g.icon .glyph {
+    fill: #20b2ff;
+}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/fw/svg/map.service.ts b/web/gui2/src/main/webapp/app/fw/svg/map.service.ts
new file mode 100644
index 0000000..391f333
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/map.service.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { GlyphDataService } from './glyphdata.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- SVG -- Map Service
+ *
+ * The Map Service provides a simple API for loading geographical maps into
+ * an SVG layer. For example, as a background to the Topology View.
+ *
+ * e.g.  var promise = MapService.loadMapInto(svgLayer, '*continental-us');
+ *
+ * The Map Service makes use of the GeoDataService to load the required data
+ * from the server and to create the appropriate geographical projection.
+ *
+ * A promise is returned to the caller, which is resolved with the
+ *  map projection once created.
+ */
+@Injectable()
+export class MapService {
+
+    constructor(
+        private gds: GlyphDataService,
+//        private q: ??QService??,
+        private log: LogService
+    ) {
+        this.log.debug('MapService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/sprite.service.ts b/web/gui2/src/main/webapp/app/fw/svg/sprite.service.ts
new file mode 100644
index 0000000..8304fc6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/sprite.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- SVG -- Sprite Service
+ *
+ *  For defining sprites and layouts (of sprites).
+ */
+@Injectable()
+export class SpriteService {
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('SpriteService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/spritedata.service.ts b/web/gui2/src/main/webapp/app/fw/svg/spritedata.service.ts
new file mode 100644
index 0000000..ced1d8b
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/spritedata.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/*
+ * ONOS GUI -- SVG -- Sprite Data Service
+ *
+ * Bundled sprite and layout definitions.
+ */
+@Injectable()
+export class SpriteDataService {
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('SpriteDataService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/svg.module.ts b/web/gui2/src/main/webapp/app/fw/svg/svg.module.ts
new file mode 100644
index 0000000..9688c30
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/svg.module.ts
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { UtilModule } from '../util/util.module';
+
+import { GeoDataService } from './geodata.service';
+import { GlyphService } from './glyph.service';
+import { GlyphDataService } from './glyphdata.service';
+import { IconService } from './icon.service';
+import { MapService } from './map.service';
+import { SpriteService } from './sprite.service';
+import { SpriteDataService } from './spritedata.service';
+import { SvgUtilService } from './svgutil.service';
+import { IconDirective } from './icon.directive';
+import { IconComponent } from './icon/icon.component';
+
+/**
+ * ONOS GUI -- Scalable Vector Graphics Module
+ */
+@NgModule({
+  exports: [
+    IconDirective,
+    IconComponent
+  ],
+  imports: [
+    CommonModule,
+    UtilModule
+  ],
+  declarations: [
+    IconDirective,
+    IconComponent
+  ],
+  providers: [
+    GeoDataService,
+    GlyphService,
+    GlyphDataService,
+    IconService,
+    MapService,
+    SpriteService,
+    SpriteDataService,
+    SvgUtilService
+  ]
+})
+export class SvgModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/svg/svgutil.service.ts b/web/gui2/src/main/webapp/app/fw/svg/svgutil.service.ts
new file mode 100644
index 0000000..51d5d2a
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/svgutil.service.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- SVG -- Util Service
+ *
+ * The SVG Util Service provides a miscellany of utility functions.
+ */
+@Injectable()
+export class SvgUtilService {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('SvgUtilService constructed');
+    }
+
+    translate(x, y) {
+        if (this.fs.isA(x) && x.length === 2 && !y) {
+            return 'translate(' + x[0] + ',' + x[1] + ')';
+        }
+        return 'translate(' + x + ',' + y + ')';
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/svg/zoom.service.ts b/web/gui2/src/main/webapp/app/fw/svg/zoom.service.ts
new file mode 100644
index 0000000..60325a6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/svg/zoom.service.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- SVG -- Zoom Service
+ */
+@Injectable()
+export class ZoomService {
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('ZoomService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/ee.service.ts b/web/gui2/src/main/webapp/app/fw/util/ee.service.ts
new file mode 100644
index 0000000..c16e4d1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/ee.service.ts
@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Util -- EE functions
+ */
+@Injectable()
+export class EeService {
+
+  constructor(
+    private log: LogService
+  ) {
+    this.log.debug('EeService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/fn.service.ts b/web/gui2/src/main/webapp/app/fw/util/fn.service.ts
new file mode 100644
index 0000000..25a0558
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/fn.service.ts
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { ActivatedRoute, Router} from '@angular/router';
+import { LogService } from '../../log.service';
+
+// Angular>=2 workaround for missing definition
+declare const InstallTrigger: any;
+
+
+// TODO Move all this trie stuff to its own class
+// Angular>=2 Tightened up on types to avoid compiler errors
+interface TrieC {
+    p: any,
+    s: string[]
+}
+// trie operation
+function _trieOp(op: string, trie, word: string, data) {
+    var p = trie,
+        w: string = word.toUpperCase(),
+        s: Array<string> = w.split(''),
+        c:TrieC = { p: p, s: s },
+        t = [],
+        x: number = 0,
+        f1 = op === '+' ? add : probe,
+        f2 = op === '+' ? insert : remove;
+
+    function add(c):TrieC {
+        var q = c.s.shift(),
+            np = c.p[q];
+
+        if (!np) {
+            c.p[q] = {};
+            np = c.p[q];
+            x = 1;
+        }
+        return { p: np, s: c.s };
+    }
+
+    function probe(c):TrieC {
+        var q = c.s.shift(),
+            k:number = Object.keys(c.p).length,
+            np = c.p[q];
+
+        t.push({ q: q, k: k, p: c.p });
+        if (!np) {
+            t = [];
+            return { p: [], s: [] };
+        }
+        return { p: np, s: c.s };
+    }
+
+    function insert() {
+        c.p._data = data;
+        return x ? 'added' : 'updated';
+    }
+
+    function remove() {
+        if (t.length) {
+            t = t.reverse();
+            while (t.length) {
+                let d = t.shift();
+                delete d.p[d.q];
+                if (d.k > 1) {
+                    t = [];
+                }
+            }
+            return 'removed';
+        }
+        return 'absent';
+    }
+
+    while (c.s.length) {
+        c = f1(c);
+    }
+    return f2();
+}
+
+// add word to trie (word will be converted to uppercase)
+// data associated with the word
+// returns 'added' or 'updated'
+function addToTrie(trie, word, data) {
+    return _trieOp('+', trie, word, data);
+}
+
+// remove word from trie (word will be converted to uppercase)
+// returns 'removed' or 'absent'
+// Angular>=2 added in quotes for data. error TS2554: Expected 4 arguments, but got 3.
+function removeFromTrie(trie, word) {
+    return _trieOp('-', trie, word, '');
+}
+
+// lookup word (converted to uppercase) in trie
+// returns:
+//    undefined if the word is not in the trie
+//    -1 for a partial match (word is a prefix to an existing word)
+//    data for the word for an exact match
+function trieLookup(trie, word) {
+    var s = word.toUpperCase().split(''),
+        p = trie,
+        n;
+
+    while (s.length) {
+        n = s.shift();
+        p = p[n];
+        if (!p) {
+            return undefined;
+        }
+    }
+    if (p._data) {
+        return p._data;
+    }
+    return -1;
+}
+
+
+/**
+ * ONOS GUI -- Util -- General Purpose Functions
+ */
+@Injectable()
+export class FnService {
+    // internal state
+    debugFlags = new Map<string, boolean>([
+//        [ "LoadingService", true ]
+    ]);
+
+    constructor(
+        private route: ActivatedRoute,
+        private log: LogService
+    ) {
+        this.route.queryParams.subscribe(params => {
+            let debugparam: string = params['debug'];
+            this.parseDebugFlags(debugparam);
+        });
+        log.debug("FnService constructed");
+    }
+
+    isF(f) {
+        return typeof f === 'function' ? f : null;
+    }
+
+    isA(a) {
+    // NOTE: Array.isArray() is part of EMCAScript 5.1
+        return Array.isArray(a) ? a : null;
+    }
+
+    isS(s) {
+        return typeof s === 'string' ? s : null;
+    }
+
+    isO(o) {
+        return (o && typeof o === 'object' && o.constructor === Object) ? o : null;
+    }
+
+//    contains: contains,
+//    areFunctions: areFunctions,
+//    areFunctionsNonStrict: areFunctionsNonStrict,
+//    windowSize: windowSize,
+
+    /**
+     * Returns true if current browser determined to be a mobile device
+     */
+    isMobile() {
+        var ua = window.navigator.userAgent,
+            patt = /iPhone|iPod|iPad|Silk|Android|BlackBerry|Opera Mini|IEMobile/;
+        return patt.test(ua);
+    }
+
+    /**
+     * Returns true if the current browser determined to be Chrome
+     */
+    isChrome() {
+        let isChromium = (window as any).chrome;
+        let vendorName = window.navigator.vendor;
+
+        let isOpera = window.navigator.userAgent.indexOf('OPR') > -1;
+        return (isChromium !== null &&
+        isChromium !== undefined &&
+        vendorName === 'Google Inc.' &&
+        isOpera == false);
+    }
+
+    /**
+     * Returns true if the current browser determined to be Safari
+     */
+    isSafari() {
+        return (window.navigator.userAgent.indexOf('Safari') !== -1 &&
+        window.navigator.userAgent.indexOf('Chrome') === -1);
+    }
+
+    /**
+     * Returns true if the current browser determined to be Firefox
+     */
+    isFirefox() {
+        return typeof InstallTrigger !== 'undefined';
+    }
+
+    /**
+     * Return the given string with the first character capitalized.
+     */
+    cap(s) {
+        return s ? s[0].toUpperCase() + s.slice(1).toLowerCase() : s;
+    }
+
+    /**
+     * output debug message to console, if debug tag set...
+     * e.g. fs.debug('mytag', arg1, arg2, ...)
+     */
+    debug(tag, ...args) {
+        if (this.debugFlags.get(tag)) {
+            this.log.debug(tag, args.join());
+        }
+    }
+
+    parseDebugFlags(dbgstr: string): void {
+        let bits = dbgstr ? dbgstr.split(',') : [];
+        bits.forEach(function (key) {
+            this.debugFlags.set(key, true);
+        });
+        this.log.debug('Debug flags:', dbgstr);
+    }
+
+    /**
+      * Return true if the given debug flag was specified in the query params
+      */
+    debugOn(tag: string): boolean {
+        return this.debugFlags.get(tag);
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/key.service.ts b/web/gui2/src/main/webapp/app/fw/util/key.service.ts
new file mode 100644
index 0000000..b10b643
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/key.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Util -- Key Handler Service
+ */
+@Injectable()
+export class KeyService {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('KeyService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/lion.service.ts b/web/gui2/src/main/webapp/app/fw/util/lion.service.ts
new file mode 100644
index 0000000..0090734
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/lion.service.ts
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * A definition of Lion data
+ */
+interface Lion {
+    locale: any;
+    lion: any;
+}
+
+/**
+ * ONOS GUI -- Lion -- Localization Utilities
+ */
+@Injectable()
+export class LionService {
+
+    ubercache: any[];
+
+    constructor(
+        private log: LogService,
+        private wss: WebSocketService
+    ) {
+        this.log.debug('LionService constructed');
+    }
+
+    /* returns a lion bundle (function) for the given bundle ID
+     * returns a function that takes a string and returns a string
+     */
+    bundle(bundleId: string): (string) => string {
+        let bundle = this.ubercache[bundleId];
+
+        if (!bundle) {
+            this.log.warn('No lion bundle registered:', bundleId);
+            bundle = {};
+        }
+
+        return this.getKey;
+    }
+
+    getKey(key: string): string {
+        return this.bundle[key] || '%' + key + '%';
+    }
+
+    /* handler for uberlion event..
+     */
+    uberlion(data: Lion) {
+        this.ubercache = data.lion;
+
+        this.log.info('LION service: Locale... [' + data.locale + ']');
+        this.log.info('LION service: Bundles installed...');
+
+        for (let p in this.ubercache) {
+            if (this.ubercache[p]) {
+                this.log.info('            :=> ', p);
+            }
+        }
+
+        this.log.debug('LION service: uber-lion bundle received:', data);
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/prefs.service.ts b/web/gui2/src/main/webapp/app/fw/util/prefs.service.ts
new file mode 100644
index 0000000..3cef9b6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/prefs.service.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Util -- User Preference Service
+ */
+@Injectable()
+export class PrefsService {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService,
+        private wss: WebSocketService
+    ) {
+        this.log.debug('PrefsService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/random.service.ts b/web/gui2/src/main/webapp/app/fw/util/random.service.ts
new file mode 100644
index 0000000..5ec71b5
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/random.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Random -- Encapsulated randomness
+ */
+@Injectable()
+export class RandomService {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('RandomService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/theme.service.ts b/web/gui2/src/main/webapp/app/fw/util/theme.service.ts
new file mode 100644
index 0000000..884fe5d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/theme.service.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+
+/**
+ * ONOS GUI -- Util -- Theme Service
+ */
+@Injectable()
+export class ThemeService {
+    themes: string[] = ['light', 'dark'];
+    thidx: number = 0;
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('ThemeService constructed');
+    }
+
+    getTheme(): string {
+        return this.themes[this.thidx];
+    }
+
+    themeStr(): string {
+        return this.themes.join(' ');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/util/util.module.ts b/web/gui2/src/main/webapp/app/fw/util/util.module.ts
new file mode 100644
index 0000000..293d8e9
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/util/util.module.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { EeService } from './ee.service';
+import { FnService } from './fn.service';
+import { KeyService } from './key.service';
+import { LionService } from './lion.service';
+import { PrefsService } from './prefs.service';
+import { RandomService } from './random.service';
+import { ThemeService } from './theme.service';
+
+/**
+ * ONOS GUI -- Utilities Module
+ */
+@NgModule({
+  imports: [
+    CommonModule
+  ],
+  declarations: [],
+  providers: [
+    EeService,
+    FnService,
+    KeyService,
+    LionService,
+    PrefsService,
+    RandomService,
+    ThemeService
+  ]
+})
+export class UtilModule { }
diff --git a/web/gui2/src/main/webapp/app/fw/widget/button.service.ts b/web/gui2/src/main/webapp/app/fw/widget/button.service.ts
new file mode 100644
index 0000000..da6cbab
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/button.service.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { IconService } from '../svg/icon.service';
+import { LogService } from '../../log.service';
+import { TooltipService } from './tooltip.service';
+
+/**
+ * ONOS GUI -- Widget -- Button Service
+ */
+@Injectable()
+export class ButtonService {
+
+    constructor(
+        private is: IconService,
+        private fs: FnService,
+        private log: LogService,
+        private tts: TooltipService
+    ) {
+        this.log.debug('ButtonService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/chartbuilder.service.ts b/web/gui2/src/main/webapp/app/fw/widget/chartbuilder.service.ts
new file mode 100644
index 0000000..1ed93df
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/chartbuilder.service.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LoadingService } from '../layer/loading.service';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Widget -- Chart Service
+ */
+@Injectable()
+export class ChartBuilderService {
+
+    constructor(
+        private fs: FnService,
+        private ls: LoadingService,
+        private log: LogService,
+        private wss: WebSocketService
+    ) {
+        this.log.debug('ChartBuilderService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/flashchanges.directive.ts b/web/gui2/src/main/webapp/app/fw/widget/flashchanges.directive.ts
new file mode 100644
index 0000000..1a5594f
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/flashchanges.directive.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Flash Changes Directive
+ */
+@Directive({
+  selector: '[onosFlashChanges]'
+})
+export class FlashChangesDirective {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('FlashChangesDirective constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/list.service.ts b/web/gui2/src/main/webapp/app/fw/widget/list.service.ts
new file mode 100644
index 0000000..3d31ab6
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/list.service.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- List Service
+ */
+@Injectable()
+export class ListService {
+
+    constructor(
+        private log: LogService
+    ) {
+        this.log.debug('ListService constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/sortableheader.directive.ts b/web/gui2/src/main/webapp/app/fw/widget/sortableheader.directive.ts
new file mode 100644
index 0000000..71c1df3
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/sortableheader.directive.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { IconService } from '../svg/icon.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Sortable Header Directive
+ */
+@Directive({
+  selector: '[onosSortableHeader]'
+})
+export class SortableHeaderDirective {
+
+    constructor(
+        private icon: IconService,
+        private log: LogService
+    ) {
+        this.log.debug('SortableHeaderDirective constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/tablebuilder.service.ts b/web/gui2/src/main/webapp/app/fw/widget/tablebuilder.service.ts
new file mode 100644
index 0000000..6c804d1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/tablebuilder.service.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LoadingService } from '../layer/loading.service';
+import { LogService } from '../../log.service';
+import { WebSocketService } from '../remote/websocket.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Builder Service
+ */
+@Injectable()
+export class TableBuilderService {
+
+  constructor(
+    private fs: FnService,
+    private ls: LoadingService,
+    private log: LogService,
+    private wss: WebSocketService
+  ) {
+    this.log.debug('TableBuilderService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/tabledetail.service.ts b/web/gui2/src/main/webapp/app/fw/widget/tabledetail.service.ts
new file mode 100644
index 0000000..76a5764
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/tabledetail.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Detail Panel Service
+ */
+@Injectable()
+export class TableDetailService {
+
+  constructor(
+    private fs: FnService,
+    private log: LogService,
+  ) {
+    this.log.debug('TableDetailService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/tableresize.directive.ts b/web/gui2/src/main/webapp/app/fw/widget/tableresize.directive.ts
new file mode 100644
index 0000000..bd25919
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/tableresize.directive.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+import { MastService } from '../mast/mast.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Resize Directive
+ */
+@Directive({
+  selector: '[onosTableResize]'
+})
+export class TableResizeDirective {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService,
+        private ms: MastService
+    ) {
+        this.log.debug('TableResizeDirective constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/toolbar.service.ts b/web/gui2/src/main/webapp/app/fw/widget/toolbar.service.ts
new file mode 100644
index 0000000..3681c80
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/toolbar.service.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+
+import { ButtonService } from './button.service';
+import { FnService } from '../util/fn.service';
+import { IconService } from '../svg/icon.service';
+import { LogService } from '../../log.service';
+import { PanelService } from '../layer/panel.service';
+
+/**
+ * ONOS GUI -- Widget -- Toolbar Service
+ * TODO: Augment service to allow toolbars to exist on right edge of screen
+ * TODO: also - make toolbar more object aware (rows etc.)
+ */
+@Injectable()
+export class ToolbarService {
+
+  constructor(
+    private fs: FnService,
+    private bns: ButtonService,
+    private is: IconService,
+    private log: LogService,
+    private ps: PanelService,
+  ) {
+    this.log.debug('ToolbarService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/tooltip.directive.ts b/web/gui2/src/main/webapp/app/fw/widget/tooltip.directive.ts
new file mode 100644
index 0000000..92f8ae3
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/tooltip.directive.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- Tooltip Directive
+ */
+@Directive({
+  selector: '[onosTooltip]'
+})
+export class TooltipDirective {
+
+    constructor(
+        private fs: FnService,
+        private log: LogService
+    ) {
+        this.log.debug('TooltipDirective constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/tooltip.service.ts b/web/gui2/src/main/webapp/app/fw/widget/tooltip.service.ts
new file mode 100644
index 0000000..6b08779
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/tooltip.service.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { FnService } from '../util/fn.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Widget -- Tooltip Service
+ */
+@Injectable()
+export class TooltipService {
+
+  constructor(
+      private fs: FnService,
+      private log: LogService,
+  ) {
+    this.log.debug('TooltipService constructed');
+  }
+
+}
diff --git a/web/gui2/src/main/webapp/app/fw/widget/widget.module.ts b/web/gui2/src/main/webapp/app/fw/widget/widget.module.ts
new file mode 100644
index 0000000..2e7a0ea
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/widget/widget.module.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { LayerModule } from '../layer/layer.module';
+import { RemoteModule } from '../remote/remote.module';
+import { SvgModule } from '../svg/svg.module';
+import { UtilModule } from '../util/util.module';
+
+import { ButtonService } from './button.service';
+import { ChartBuilderService } from './chartbuilder.service';
+import { ListService } from './list.service';
+import { TableBuilderService } from './tablebuilder.service';
+import { TableDetailService } from './tabledetail.service';
+import { ToolbarService } from './toolbar.service';
+import { TooltipService } from './tooltip.service';
+import { TooltipDirective } from './tooltip.directive';
+import { SortableHeaderDirective } from './sortableheader.directive';
+import { TableResizeDirective } from './tableresize.directive';
+import { FlashChangesDirective } from './flashchanges.directive';
+
+/**
+ * ONOS GUI -- Widgets Module
+ */
+@NgModule({
+  imports: [
+    CommonModule
+    // Services have global scope and their modules don't have to be imported again
+    // It's enough to import them in the OnosModule
+  ],
+  declarations: [
+    TooltipDirective,
+    SortableHeaderDirective,
+    TableResizeDirective,
+    FlashChangesDirective
+  ],
+  providers: [
+    ButtonService,
+    ChartBuilderService,
+    ListService,
+    TableBuilderService,
+    TableDetailService,
+    TooltipService,
+    ToolbarService
+  ]
+})
+export class WidgetModule { }
diff --git a/web/gui2/src/main/webapp/app/log.service.ts b/web/gui2/src/main/webapp/app/log.service.ts
new file mode 100644
index 0000000..3dc54a1
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/log.service.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+
+export abstract class Logger {
+  debug: any;
+  info: any;
+  warn: any;
+  error: any;
+}
+
+/**
+ * ONOS GUI -- LogService
+ * Inspired by https://robferguson.org/blog/2017/09/09/a-simple-logging-service-for-angular-4/
+ */
+@Injectable()
+export class LogService extends Logger {
+  debug: any;
+  info: any;
+  warn: any;
+  error: any;
+
+  invokeConsoleMethod(type: string, args?: any): void {}
+}
diff --git a/web/gui2/src/main/webapp/app/onos.component.css b/web/gui2/src/main/webapp/app/onos.component.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.component.css
diff --git a/web/gui2/src/main/webapp/app/onos.component.html b/web/gui2/src/main/webapp/app/onos.component.html
new file mode 100644
index 0000000..566c972
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.component.html
@@ -0,0 +1,8 @@
+<div style="text-align:center" onosDetectBrowser>
+    <onos-mast></onos-mast>
+    <onos-nav></onos-nav>
+    <router-outlet></router-outlet>
+</div>
+
+
+
diff --git a/web/gui2/src/main/webapp/app/onos.component.ts b/web/gui2/src/main/webapp/app/onos.component.ts
new file mode 100644
index 0000000..a1a84de
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.component.ts
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit } from '@angular/core';
+import { LionService } from './fw/util/lion.service';
+import { LogService } from './log.service';
+import { KeyService } from './fw/util/key.service';
+import { ThemeService } from './fw/util/theme.service';
+import { GlyphService } from './fw/svg/glyph.service';
+import { VeilService } from './fw/layer/veil.service';
+import { PanelService } from './fw/layer/panel.service';
+import { FlashService } from './fw/layer/flash.service';
+import { QuickHelpService } from './fw/layer/quickhelp.service';
+import { EeService } from './fw/util/ee.service';
+import { WebSocketService } from './fw/remote/websocket.service';
+import { SpriteService } from './fw/svg/sprite.service';
+import { OnosService, View } from './onos.service';
+
+// secret sauce
+const sauce: string[] = [
+    '6:69857666',
+    '9:826970',
+    '22:8069828667',
+    '6:698570688669887967',
+    '7:6971806889847186',
+    '22:8369867682',
+    '13:736583',
+    '7:667186698384',
+    '1:857780888778876787',
+    '20:70717066',
+    '24:886774868469',
+    '17:7487696973687580739078',
+    '14:70777086',
+    '17:7287687967',
+    '11:65678869706783687184',
+    '1:80777778',
+    '9:72696982',
+    '7:857165828967',
+    '11:8867696882678869759071'
+    // Add more sauce...
+];
+
+function cap(s: string): string {
+    return s ? s[0].toUpperCase() + s.slice(1) : s;
+}
+
+/**
+ * The main ONOS Component - the root of the whole user interface
+ */
+@Component({
+  selector: 'onos-root',
+  templateUrl: './onos.component.html',
+  styleUrls: ['./onos.component.css']
+})
+export class OnosComponent implements OnInit {
+    public title = 'onos';
+
+    // view ID to help page url map.. injected via the servlet
+    viewMap: View[]  = [
+        // {INJECTED-VIEW-DATA-START}
+        // {INJECTED-VIEW-DATA-END}
+    ];
+
+    defaultView = 'topo';
+    // TODO Move this to OnosModule - warning servlet will have to be updated too
+    viewDependencies: string[] = [];
+
+    constructor (
+        private lion: LionService,
+        private ks: KeyService,
+        private ts: ThemeService,
+        private gs: GlyphService,
+        private vs: VeilService,
+        private ps: PanelService,
+        private flash: FlashService,
+        private qhs: QuickHelpService,
+        private ee: EeService,
+        private wss: WebSocketService,
+        private ss: SpriteService,
+        private log: LogService,
+        private onos: OnosService
+    ) {
+
+// This is not like onos.js of AngularJS 1.x In this new structure modules are
+// imported instead in the OnosModule. view dependencies should be there too
+//        const moduleDependencies = coreDependencies.concat(this.viewDependencies);
+
+        // Testing of debugging
+        log.debug('OnosComponent: testing logger.debug()');
+        log.info('OnosComponent: testing logger.info()');
+        log.warn('OnosComponent: testing logger.warn()');
+        log.error('OnosComponent: testing logger.error()');
+
+        log.debug('OnosComponent constructed');
+    }
+
+    ngOnInit() {
+        this.viewMap.forEach(view =>
+            this.viewDependencies.push('ov' + cap(view.id)));
+
+        this.onos.viewMap = this.viewMap;
+
+//        this.wss.createWebSocket({
+//            wsport: Window.location.search().wsport
+//        });
+
+        // TODO: Enable this   this.saucy(this.ee, this.ks);
+        this.log.debug('OnosComponent initialized');
+    }
+
+    saucy(ee, ks) {
+        const map = ee.genMap(sauce);
+        Object.keys(map).forEach(function (k) {
+            ks.addSeq(k, map[k]);
+        });
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/onos.css b/web/gui2/src/main/webapp/app/onos.css
new file mode 100644
index 0000000..fa485ac
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.css
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- core (layout) -- CSS file
+ */
+
+html {
+    font-family: 'Open Sans', sans-serif;
+    -webkit-text-size-adjust: 100%;
+    -ms-text-size-adjust: 100%;
+    height: 100%;
+}
+
+/*
+   overflow hidden is to ensure that the body does not expand to account
+   for any flyout panes, that are positioned "off screen".
+ */
+body {
+    height: 100%;
+    margin: 0;
+    overflow: hidden;
+}
+
+#view {
+    padding: 6px;
+    width: 100%;
+    height: 100%;
+}
+
+#view h2 {
+    -webkit-margin-before: 0;
+    -webkit-margin-after: 0;
+    margin: 32px 0 4px 16px;
+    padding: 0;
+    font-size: 18pt;
+    font-weight: lighter;
+}
diff --git a/web/gui2/src/main/webapp/app/onos.module.ts b/web/gui2/src/main/webapp/app/onos.module.ts
new file mode 100644
index 0000000..717893e
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.module.ts
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { BrowserModule } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { AppsModule } from './view/apps/apps.module';
+import { DeviceModule } from './view/device/device.module';
+
+import { LayerModule } from './fw/layer/layer.module';
+import { MastModule } from './fw/mast/mast.module';
+import { NavModule } from './fw/nav/nav.module';
+import { SvgModule } from './fw/svg/svg.module';
+import { RemoteModule } from './fw/remote/remote.module';
+import { UtilModule } from './fw/util/util.module';
+import { WidgetModule } from './fw/widget/widget.module';
+
+import { AppsComponent } from './view/apps/apps.component';
+import { DeviceComponent } from './view/device/device.component';
+import { OnosComponent } from './onos.component';
+import { DetectBrowserDirective } from './detectbrowser.directive';
+
+import { ConsoleLoggerService } from './consolelogger.service';
+import { LogService } from './log.service';
+import { OnosService } from './onos.service';
+
+const onosRoutes: Routes = [
+  { path: 'apps', component: AppsComponent },        // All except default should be driven by
+  { path: 'device', component: DeviceComponent },    // servlet like {INJECTED-VIEW-DATA-START}
+  { path: '**', component: DeviceComponent } //Change to Topo(2) when it's ready for normal behaviour
+]
+
+/**
+ * ONOS GUI -- Main Application Module
+ */
+@NgModule({
+  declarations: [
+    OnosComponent,
+    DetectBrowserDirective
+  ],
+  imports: [
+    AppsModule,
+    DeviceModule,
+    BrowserModule,
+    BrowserAnimationsModule,
+    LayerModule,
+    MastModule,
+    NavModule,
+    RouterModule.forRoot(onosRoutes, { enableTracing: false }),
+    SvgModule,
+    RemoteModule,
+    UtilModule, // For OnosComponent
+    WidgetModule
+  ],
+  providers: [
+    OnosService,
+    { provide: LogService, useClass: ConsoleLoggerService },
+    { provide: Window, useValue: window }
+  ],
+  bootstrap: [
+    OnosComponent,
+  ]
+})
+export class OnosModule { }
diff --git a/web/gui2/src/main/webapp/app/onos.service.ts b/web/gui2/src/main/webapp/app/onos.service.ts
new file mode 100644
index 0000000..7b4d519
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/onos.service.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { LogService } from './log.service';
+
+/**
+ * A structure of View elements for the OnosService
+ */
+export interface View {
+    id: string;
+    path: string;
+}
+
+/**
+ * ONOS GUI -- OnosService - a placeholder for the global onos variable
+ */
+@Injectable()
+export class OnosService {
+    // Global variable
+    public browser: string;
+    public mobile: boolean;
+    public viewMap: View[];
+
+    constructor (
+        private log: LogService
+    ) {
+        this.log.debug('OnosService constructed');
+    }
+}
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps.component.css b/web/gui2/src/main/webapp/app/view/apps/apps.component.css
new file mode 100644
index 0000000..a1963c0
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/apps.component.css
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Applications View (layout) -- CSS file
+ */
+
+#ov-app h2 {
+    display: inline-block;
+}
+
+#ov-app div.ctrl-btns {
+    width: 290px;
+}
+
+/* -- Drag-n-Drop oar file upload -- */
+#ov-app form#inputFileForm,
+#ov-app input#uploadFile {
+    display: none;
+}
+
+.dropping {
+
+}
+
+/* -- Confirmation Dialog -- */
+#app-dialog {
+    top: 140px;
+    padding: 12px;
+}
+
+#app-dialog p {
+    font-size: 12pt;
+}
+
+#app-dialog p.strong {
+    font-weight: bold;
+    padding: 8px;
+    text-align: center;
+}
+
+/* -- Details Panel -- */
+#application-details-panel.floatpanel {
+    z-index: 0;
+}
+
+#application-details-panel.floatpanel a {
+    font-weight: bold;
+}
+
+#application-details-panel .container {
+    padding: 0 30px;
+    overflow-y: scroll;
+}
+
+#application-details-panel .close-btn {
+    position: absolute;
+    right: 26px;
+    top: 26px;
+    cursor: pointer;
+}
+
+#application-details-panel .app-icon {
+    display: inline-block;
+    padding: 0 6px 0 0;
+    vertical-align: middle;
+}
+
+#application-details-panel h2 {
+    display: inline-block;
+    margin: 12px 0 6px 0;
+    font-size: 11pt;
+    font-variant: small-caps;
+    text-transform: uppercase;
+}
+
+#application-details-panel .top .app-title {
+    width: 90%;
+    height: 62px;
+    font-size: 16pt;
+    font-weight: lighter;
+    overflow: hidden;
+    white-space: nowrap;
+    padding: 0 12px 0 2px;
+    margin-top: 19px;
+    margin-bottom: 5px;
+}
+
+#application-details-panel .top div.left {
+    float: left;
+    padding: 12px 12px 0 3px;
+}
+
+#application-details-panel .top div.right {
+    display: inline-block;
+    overflow: hidden;
+    width: 320px;
+}
+
+#application-details-panel td.label,
+#application-details-panel .app-url i {
+    font-weight: bold;
+    text-align: right;
+    font-size: 10pt;
+    padding-right: 6px;
+}
+
+#application-details-panel td.value-bold {
+    font-weight: bold;
+}
+
+#application-details-panel .app-url {
+    padding: 10px 6px 6px;
+    overflow: hidden;
+    clear: left;
+}
+
+#application-details-panel hr {
+    width: 100%;
+    margin: 12px auto;
+}
+
+#application-details-panel .middle {
+    padding: 7px 0 7px 6px;
+}
+
+#application-details-panel .bottom {
+    padding: 0px;
+}
+
+#application-details-panel .bottom table {
+    border-spacing: 0;
+    width: 100%;
+}
+
+#application-details-panel .bottom td {
+    margin-left: -6px;
+    padding: 6px 6px;
+    text-align: left;
+}
+
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps.component.html b/web/gui2/src/main/webapp/app/view/apps/apps.component.html
new file mode 100644
index 0000000..90f9a16
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/apps.component.html
@@ -0,0 +1,3 @@
+<div id="ov-app">
+    <p>apps works!</p>
+</div>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps.component.ts b/web/gui2/src/main/webapp/app/view/apps/apps.component.ts
new file mode 100644
index 0000000..5eaa38f
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/apps.component.ts
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit } from '@angular/core';
+import { DialogService } from '../../fw/layer/dialog.service';
+import { FnService } from '../../fw/util/fn.service';
+import { IconService } from '../../fw/svg/icon.service';
+import { KeyService } from '../../fw/util/key.service';
+import { LionService } from '../../fw/util/lion.service';
+import { LogService } from '../../log.service';
+import { PanelService } from '../../fw/layer/panel.service';
+import { TableBuilderService } from '../../fw/widget/tablebuilder.service';
+import { UrlFnService } from '../../fw/remote/urlfn.service';
+import { WebSocketService } from '../../fw/remote/websocket.service';
+
+/**
+ * ONOS GUI -- Apps View Component
+ */
+@Component({
+  selector: 'onos-apps',
+  templateUrl: './apps.component.html',
+  styleUrls: ['./apps.component.css']
+})
+export class AppsComponent implements OnInit {
+
+    constructor(
+        private fs: FnService,
+        private ds: DialogService,
+        private is: IconService,
+        private ks: KeyService,
+        private ls: LionService,
+        private log: LogService,
+        private ps: PanelService,
+        private tbs: TableBuilderService,
+        private ufs: UrlFnService,
+        private wss: WebSocketService,
+        private window: Window
+    ) {
+        this.log.debug('AppsComponent constructed');
+    }
+
+    ngOnInit() {
+        this.log.debug('AppsComponent initialized');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps.module.ts b/web/gui2/src/main/webapp/app/view/apps/apps.module.ts
new file mode 100644
index 0000000..3083b55
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/apps.module.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { AppsComponent } from './apps.component';
+import { TriggerFormDirective } from './triggerform.directive';
+
+/**
+ * ONOS GUI -- Apps View Module
+ *
+ * Note: This has been updated from onos-gui-1.0.0 where it was called 'app'
+ * whereas here it is now called 'apps'. This is to avoid any confusion with
+ * the 'app' folder which is the root of the complete framework
+ */
+@NgModule({
+    exports: [
+        AppsComponent
+    ],
+    imports: [
+        CommonModule
+    ],
+    declarations: [
+        AppsComponent,
+        TriggerFormDirective
+    ]
+})
+export class AppsModule { }
diff --git a/web/gui2/src/main/webapp/app/view/apps/apps.theme.css b/web/gui2/src/main/webapp/app/view/apps/apps.theme.css
new file mode 100644
index 0000000..3de7ad8
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/apps.theme.css
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Applications View (theme) -- CSS file
+ */
+
+/* -- Drag-n-Drop OAR files -- */
+div.dropping {
+    border: solid 3px #0095d6;
+}
+
+
+/* -- confirmation dialog -- */
+.light #app-dialog p.strong {
+    color: white;
+    background-color: #ce5b58;
+}
+
+.light #app-dialog.floatpanel.dialog {
+    background-color: #ffffff;
+}
+
+/* ========== DARK Theme ========== */
+
+
+.dark .app-title {
+    color: #dddddd;
+}
+
+/* -- confirmation dialog -- */
+.dark #app-dialog p.strong {
+    color: red;
+    background-color: #ecd98e;
+}
+.dark #app-dialog.floatpanel.dialog {
+    background-color: #282528;
+    color:#ddddee;
+}
diff --git a/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts b/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts
new file mode 100644
index 0000000..2bf9cd7
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+
+/**
+ * ONOS GUI -- Apps -- Trigger Form Directive
+ */
+@Directive({
+  selector: '[onosTriggerForm]'
+})
+export class TriggerFormDirective {
+
+  constructor() { }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/device/device.component.css b/web/gui2/src/main/webapp/app/view/device/device.component.css
new file mode 100644
index 0000000..c578112
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/device.component.css
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Device View (layout) -- CSS file
+ */
+
+#ov-device h2 {
+    display: inline-block;
+}
+
+#ov-device div.ctrl-btns {
+}
+
+
+/* More in generic panel.css */
+
+#device-details-panel.floatpanel {
+    z-index: 0;
+}
+
+
+#device-details-panel .container {
+    padding: 8px 12px;
+}
+
+#device-details-panel .close-btn {
+    position: absolute;
+    right: 12px;
+    top: 12px;
+    cursor: pointer;
+}
+
+#device-details-panel .dev-icon {
+    display: inline-block;
+    padding: 0 6px 0 0;
+    vertical-align: middle;
+}
+
+#device-details-panel h2 {
+    display: inline-block;
+    margin: 8px 0;
+}
+
+
+#device-details-panel h2 input {
+    font-size: 0.90em;
+    width: 106%;
+}
+
+#device-details-panel .top-tables {
+    font-size: 10pt;
+    white-space: nowrap;
+}
+
+#device-details-panel .top div.left {
+    float: left;
+    padding: 0 18px 0 0;
+}
+#device-details-panel .top div.right {
+    display: inline-block;
+}
+
+#device-details-panel td.label {
+    font-weight: bold;
+    text-align: right;
+    padding-right: 6px;
+}
+
+#device-details-panel .actionBtns div {
+    padding: 12px 6px;
+}
+
+#device-details-panel hr {
+    width: 100%;
+    margin: 2px auto;
+}
+
+#device-details-panel .bottom table {
+    border-spacing: 0;
+}
+
+#device-details-panel .bottom th {
+    letter-spacing: 0.02em;
+}
+
+#device-details-panel .bottom th,
+#device-details-panel .bottom td {
+    padding: 6px 12px;
+    text-align: center;
+}
+
diff --git a/web/gui2/src/main/webapp/app/view/device/device.component.html b/web/gui2/src/main/webapp/app/view/device/device.component.html
new file mode 100644
index 0000000..febc99a
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/device.component.html
@@ -0,0 +1,3 @@
+<div id="ov-device">
+    <p>device works!</p>
+</div>
diff --git a/web/gui2/src/main/webapp/app/view/device/device.component.ts b/web/gui2/src/main/webapp/app/view/device/device.component.ts
new file mode 100644
index 0000000..db42c4d
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/device.component.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Component, OnInit } from '@angular/core';
+import { DetailsPanelService } from '../../fw/layer/detailspanel.service';
+import { FnService } from '../../fw/util/fn.service';
+import { IconService } from '../../fw/svg/icon.service';
+import { KeyService } from '../../fw/util/key.service';
+import { LoadingService } from '../../fw/layer/loading.service';
+import { LogService } from '../../log.service';
+import { MastService } from '../../fw/mast/mast.service';
+import { NavService } from '../../fw/nav/nav.service';
+import { PanelService } from '../../fw/layer/panel.service';
+import { TableBuilderService } from '../../fw/widget/tablebuilder.service';
+import { TableDetailService } from '../../fw/widget/tabledetail.service';
+import { WebSocketService } from '../../fw/remote/websocket.service';
+
+/**
+ * ONOS GUI -- Device View Component
+ */
+@Component({
+  selector: 'onos-device',
+  templateUrl: './device.component.html',
+  styleUrls: ['./device.component.css']
+})
+export class DeviceComponent implements OnInit {
+
+    constructor(
+        private dps: DetailsPanelService,
+        private fs: FnService,
+        private is: IconService,
+        private ks: KeyService,
+        private log: LogService,
+        private mast: MastService,
+        private nav: NavService,
+        private ps: PanelService,
+        private tbs: TableBuilderService,
+        private tds: TableDetailService,
+        private wss: WebSocketService,
+        private ls: LoadingService, // TODO: Remove - already added through tbs
+        private window: Window
+    ) {
+        this.log.debug('DeviceComponent constructed');
+    }
+
+    ngOnInit() {
+        this.log.debug('DeviceComponent initialized');
+        // TODO: Remove this - it's only for demo purposes
+        this.ls.startAnim();
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/app/view/device/device.module.ts b/web/gui2/src/main/webapp/app/view/device/device.module.ts
new file mode 100644
index 0000000..9cd50cb
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/device.module.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { DeviceComponent } from './device.component';
+import { DeviceDetailsPanelDirective } from './devicedetailspanel.directive';
+
+/**
+ * ONOS GUI -- Device View Module
+ */
+@NgModule({
+  exports: [
+    DeviceComponent
+  ],
+  imports: [
+    CommonModule
+  ],
+  declarations: [
+    DeviceComponent,
+    DeviceDetailsPanelDirective
+  ]
+})
+export class DeviceModule { }
diff --git a/web/gui2/src/main/webapp/app/view/device/device.theme.css b/web/gui2/src/main/webapp/app/view/device/device.theme.css
new file mode 100644
index 0000000..df0f139
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/device.theme.css
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Device View (theme) -- CSS file
+ */
+
+.light #device-details-panel .bottom th {
+    background-color: #e5e5e6;
+}
+
+.light #device-details-panel .bottom tr:nth-child(odd) {
+    background-color: #fbfbfb;
+}
+.light #device-details-panel .bottom tr:nth-child(even) {
+    background-color: #f4f4f4;
+}
+
diff --git a/web/gui2/src/main/webapp/app/view/device/devicedetailspanel.directive.ts b/web/gui2/src/main/webapp/app/view/device/devicedetailspanel.directive.ts
new file mode 100644
index 0000000..13e7e69
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/device/devicedetailspanel.directive.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Directive } from '@angular/core';
+import { KeyService } from '../../fw/util/key.service';
+import { LogService } from '../../log.service';
+
+/**
+ * ONOS GUI -- Device Details Panel Directive
+ *
+ * TODO: figure out if this should be a directive or a component. In the old
+ * code it was a directive, but was referred to in device.html like a component
+ * would be
+ */
+@Directive({
+  selector: '[onosDeviceDetailsPanel]'
+})
+export class DeviceDetailsPanelDirective {
+
+    constructor(
+        private ks: KeyService,
+        private log: LogService,
+        private window: Window
+    ) {
+        this.log.debug('DeviceDetailsPanelDirective constructed');
+    }
+
+}
diff --git a/web/gui2/src/main/webapp/data/img/apple-touch-icon.png b/web/gui2/src/main/webapp/data/img/apple-touch-icon.png
new file mode 100644
index 0000000..3bf5eb6
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/apple-touch-icon.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/dropdown-icon.png b/web/gui2/src/main/webapp/data/img/dropdown-icon.png
new file mode 100644
index 0000000..eb57f17
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/dropdown-icon.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-01.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-01.png
new file mode 100644
index 0000000..5f209a3
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-01.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-02.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-02.png
new file mode 100644
index 0000000..18f371b
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-02.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-03.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-03.png
new file mode 100644
index 0000000..00eb3a8
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-03.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-04.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-04.png
new file mode 100644
index 0000000..5977f6e
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-04.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-05.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-05.png
new file mode 100644
index 0000000..1da5d28
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-05.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-06.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-06.png
new file mode 100644
index 0000000..871b9a6
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-06.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-07.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-07.png
new file mode 100644
index 0000000..7538b84
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-07.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-08.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-08.png
new file mode 100644
index 0000000..a7f3233
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-08.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-09.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-09.png
new file mode 100644
index 0000000..8c311df
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-09.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-10.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-10.png
new file mode 100644
index 0000000..cf59c93
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-10.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-11.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-11.png
new file mode 100644
index 0000000..e18c93a
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-11.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-12.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-12.png
new file mode 100644
index 0000000..c63c240
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-12.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-13.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-13.png
new file mode 100644
index 0000000..a6b3c7a
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-13.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-14.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-14.png
new file mode 100644
index 0000000..046a132
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-14.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-15.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-15.png
new file mode 100644
index 0000000..c22108f
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-15.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/dark/load-16.png b/web/gui2/src/main/webapp/data/img/loading/dark/load-16.png
new file mode 100644
index 0000000..b685ad5
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/dark/load-16.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-01.png b/web/gui2/src/main/webapp/data/img/loading/light/load-01.png
new file mode 100644
index 0000000..5cfedd6
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-01.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-02.png b/web/gui2/src/main/webapp/data/img/loading/light/load-02.png
new file mode 100644
index 0000000..ec726fa
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-02.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-03.png b/web/gui2/src/main/webapp/data/img/loading/light/load-03.png
new file mode 100644
index 0000000..d815032
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-03.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-04.png b/web/gui2/src/main/webapp/data/img/loading/light/load-04.png
new file mode 100644
index 0000000..6b97e0e
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-04.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-05.png b/web/gui2/src/main/webapp/data/img/loading/light/load-05.png
new file mode 100644
index 0000000..7b20749
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-05.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-06.png b/web/gui2/src/main/webapp/data/img/loading/light/load-06.png
new file mode 100644
index 0000000..4926bcc
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-06.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-07.png b/web/gui2/src/main/webapp/data/img/loading/light/load-07.png
new file mode 100644
index 0000000..27c95fd
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-07.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-08.png b/web/gui2/src/main/webapp/data/img/loading/light/load-08.png
new file mode 100644
index 0000000..0709c12
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-08.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-09.png b/web/gui2/src/main/webapp/data/img/loading/light/load-09.png
new file mode 100644
index 0000000..8318b43
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-09.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-10.png b/web/gui2/src/main/webapp/data/img/loading/light/load-10.png
new file mode 100644
index 0000000..57dd853
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-10.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-11.png b/web/gui2/src/main/webapp/data/img/loading/light/load-11.png
new file mode 100644
index 0000000..549c3c2
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-11.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-12.png b/web/gui2/src/main/webapp/data/img/loading/light/load-12.png
new file mode 100644
index 0000000..17bb059
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-12.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-13.png b/web/gui2/src/main/webapp/data/img/loading/light/load-13.png
new file mode 100644
index 0000000..b52e5d7
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-13.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-14.png b/web/gui2/src/main/webapp/data/img/loading/light/load-14.png
new file mode 100644
index 0000000..78f6183f7
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-14.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-15.png b/web/gui2/src/main/webapp/data/img/loading/light/load-15.png
new file mode 100644
index 0000000..e29dbc5
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-15.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/loading/light/load-16.png b/web/gui2/src/main/webapp/data/img/loading/light/load-16.png
new file mode 100644
index 0000000..74c7933
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/loading/light/load-16.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/masthead-logo-mojo.png b/web/gui2/src/main/webapp/data/img/masthead-logo-mojo.png
new file mode 100644
index 0000000..969c5fb
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/masthead-logo-mojo.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/nav-menu-mojo.png b/web/gui2/src/main/webapp/data/img/nav-menu-mojo.png
new file mode 100644
index 0000000..d8cd6d5
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/nav-menu-mojo.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/nav-menu.png b/web/gui2/src/main/webapp/data/img/nav-menu.png
new file mode 100644
index 0000000..07bbcf1
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/nav-menu.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/onos-logo-fliprotate.png b/web/gui2/src/main/webapp/data/img/onos-logo-fliprotate.png
new file mode 100644
index 0000000..7368017
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/onos-logo-fliprotate.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/onos-logo.lg.png b/web/gui2/src/main/webapp/data/img/onos-logo.lg.png
new file mode 100644
index 0000000..afbd438
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/onos-logo.lg.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/data/img/onos-logo.png b/web/gui2/src/main/webapp/data/img/onos-logo.png
new file mode 100644
index 0000000..8688cd6
--- /dev/null
+++ b/web/gui2/src/main/webapp/data/img/onos-logo.png
Binary files differ
diff --git a/web/gui2/src/main/webapp/environments/environment.prod.ts b/web/gui2/src/main/webapp/environments/environment.prod.ts
new file mode 100644
index 0000000..3612073
--- /dev/null
+++ b/web/gui2/src/main/webapp/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+  production: true
+};
diff --git a/web/gui2/src/main/webapp/environments/environment.ts b/web/gui2/src/main/webapp/environments/environment.ts
new file mode 100644
index 0000000..f649333
--- /dev/null
+++ b/web/gui2/src/main/webapp/environments/environment.ts
@@ -0,0 +1,9 @@
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+  production: false,
+  isDebugMode: true
+};
diff --git a/web/gui2/src/main/webapp/error.html b/web/gui2/src/main/webapp/error.html
new file mode 100644
index 0000000..564e284
--- /dev/null
+++ b/web/gui2/src/main/webapp/error.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>ONOS Login</title>
+
+    <style type="text/css">
+        img {
+            margin: 24px;
+        }
+        td {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            text-align: left;
+            padding: 4px;
+        }
+        input {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            padding: 3px;
+        }
+
+        input[type="submit"] {
+            margin-top: 20px;
+            margin-left: auto;
+            margin-right: auto;
+            display: block;
+            padding: 4px 16px;
+            background-color: #CE5650;
+            color: #fff;
+            /*width: 100%; /!* width of image *!/*/
+            height: 32px;
+            border-radius: 3px;
+            border: 0;
+            -moz-outline-radius: 6px;
+        }
+
+        input[type="submit"]:hover {
+            border-radius: 3px;
+            border: 1px;
+            border-color: #fff;
+            border-style: solid;
+            box-shadow: 0px 0px 10px #3399ff;
+            outline-style: solid;
+            outline-width: 3px;
+            outline-color: #3399ff;
+        }
+
+        #error {
+            margin: 16px auto;
+            color: #CE5650;
+            text-align: center;
+
+        }
+    </style>
+</head>
+<body>
+<div align="center">
+    <img src="data/img/onos-logo.lg.png"/>
+
+    <form method="post" action="j_security_check">
+        <table>
+            <tr>
+                <td>User:</td>
+                <td><input id="username" name="j_username" type="text" autofocus/></td>
+            </tr>
+            <tr>
+                <td>Password:</td>
+                <td><input id="password" name="j_password" type="password"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><input id="submit" type="submit" value="Login"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><div id="error">Incorrect login credentials!</div></td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/index.html b/web/gui2/src/main/webapp/index.html
new file mode 100644
index 0000000..83d2b6c
--- /dev/null
+++ b/web/gui2/src/main/webapp/index.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<!--
+~ Copyright 2014-present Open Networking Foundation
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~     http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<html>
+<head>
+    <meta charset="utf-8">
+    <link rel="shortcut icon" href="data/img/onos-logo.png">
+
+    <link rel="apple-touch-icon" href="data/img/apple-touch-icon.png">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700'
+          rel='stylesheet' type='text/css'>
+    <link href="app/fw/layer/loading.service.css" rel='stylesheet' type='text/css'>
+    <base href="/">
+    <title>ONOS</title>
+
+    <!-- {INJECTED-USER-START} -->
+    <!-- {INJECTED-USER-END} -->
+
+    <!-- ONOS UI Framework included here -->
+    <!--<script src="onos.js"></script>-->
+    <!--<script src="dist/onos.js"></script>-->
+
+    <!-- Framework and library stylesheets included here -->
+    <!--<link rel="stylesheet" href="dist/onos.css">-->
+
+    <!-- Contributed javascript injected here -->
+    <!-- {INJECTED-JAVASCRIPT-START} -->
+    <!-- {INJECTED-JAVASCRIPT-END} -->
+
+    <!-- Contributed stylesheets injected here -->
+    <!-- {INJECTED-STYLESHEETS-START} -->
+    <!-- {INJECTED-STYLESHEETS-END} -->
+
+</head>
+<body class="light">
+    <onos-root></onos-root>
+
+<!--<script>-->
+    <!--&lt;!&ndash; Inject user agent info into html element to allow CSS sensitivity. &ndash;&gt;-->
+    <!--(function () {-->
+        <!--var t = ('ontouchstart' in window) || ('onmsgesturechange' in window);-->
+        <!--d3.select(document.documentElement)-->
+            <!--.attr('data-useragent', navigator.userAgent)-->
+            <!--.attr('data-platform', navigator.platform)-->
+            <!--.classed('touch', t);-->
+    <!--}());-->
+<!--</script>-->
+</body>
+</html>
diff --git a/web/gui2/src/main/webapp/login.html b/web/gui2/src/main/webapp/login.html
new file mode 100644
index 0000000..d05260f
--- /dev/null
+++ b/web/gui2/src/main/webapp/login.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>ONOS Login</title>
+
+    <style type="text/css">
+        img {
+            margin: 24px;
+        }
+        td {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            text-align: left;
+            padding: 4px;
+        }
+        input {
+            font: normal 16px Helvetica, Arial, sans-serif !important;
+            padding: 3px;
+        }
+
+        input[type="submit"] {
+            margin-top: 20px;
+            margin-left: auto;
+            margin-right: auto;
+            display: block;
+            padding: 4px 16px;
+            background-color: #CE5650;
+            color: #fff;
+            /*width: 100%; /!* width of image *!/*/
+            height: 32px;
+            border-radius: 3px;
+            border: 0;
+            -moz-outline-radius: 6px;
+        }
+
+        input[type="submit"]:hover {
+            border-radius: 3px;
+            border: 1px;
+            border-color: #fff;
+            border-style: solid;
+            box-shadow: 0px 0px 10px #3399ff;
+            outline-style: solid;
+            outline-width: 3px;
+            outline-color: #3399ff;
+        }
+    </style>
+</head>
+<body>
+<div align="center">
+    <img src="data/img/onos-logo.lg.png"/>
+
+    <form method="post" action="j_security_check">
+        <table>
+            <tr>
+                <td>User:</td>
+                <td><input id="username" name="j_username" type="text" autofocus/></td>
+            </tr>
+            <tr>
+                <td>Password:</td>
+                <td><input id="password" name="j_password" type="password"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><input id="submit" type="submit" value="Login"/></td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/nav.html b/web/gui2/src/main/webapp/nav.html
new file mode 100644
index 0000000..453efc3
--- /dev/null
+++ b/web/gui2/src/main/webapp/nav.html
@@ -0,0 +1,4 @@
+<!-- {INJECTED-VIEW-NAV-START} -->
+<a ng-click="navCtrl.hideNav()" href="#/topo">Network Topology</a>
+<a ng-click="navCtrl.hideNav()" href="#/device">Device List</a>
+<!-- {INJECTED-VIEW-NAV-END} -->
diff --git a/web/gui2/src/main/webapp/not-ready.html b/web/gui2/src/main/webapp/not-ready.html
new file mode 100644
index 0000000..7679664
--- /dev/null
+++ b/web/gui2/src/main/webapp/not-ready.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+  ~ Copyright 2015-present Open Networking Foundation
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<html>
+<link>
+    <meta charset="utf-8">
+    <link rel="shortcut icon" href="data/img/onos-logo.png">
+
+    <link rel="apple-touch-icon" href="data/img/apple-touch-icon.png">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <meta http-equiv="refresh" content="5;URL=/onos/ui">
+
+    <style>
+        body { padding: 16px; }
+        h1 { font-family: Arial, Helvetica, sans-serif }
+    </style>
+
+    <title>ONOS</title>
+
+</head>
+<body>
+<h1>ONOS GUI not ready yet... please stand by...</h1>
+</body>
+</html>
diff --git a/web/gui2/src/main/webapp/onos.ts b/web/gui2/src/main/webapp/onos.ts
new file mode 100644
index 0000000..cf76512
--- /dev/null
+++ b/web/gui2/src/main/webapp/onos.ts
@@ -0,0 +1,12 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { OnosModule } from './app/onos.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+  enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(OnosModule)
+  .catch(err => console.log(err));
diff --git a/web/gui2/src/main/webapp/polyfills.ts b/web/gui2/src/main/webapp/polyfills.ts
new file mode 100644
index 0000000..d68672f
--- /dev/null
+++ b/web/gui2/src/main/webapp/polyfills.ts
@@ -0,0 +1,66 @@
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ *      file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+// import 'core-js/es6/symbol';
+// import 'core-js/es6/object';
+// import 'core-js/es6/function';
+// import 'core-js/es6/parse-int';
+// import 'core-js/es6/parse-float';
+// import 'core-js/es6/number';
+// import 'core-js/es6/math';
+// import 'core-js/es6/string';
+// import 'core-js/es6/date';
+// import 'core-js/es6/array';
+// import 'core-js/es6/regexp';
+// import 'core-js/es6/map';
+// import 'core-js/es6/weak-map';
+// import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
+
+/** IE10 and IE11 requires the following for the Reflect API. */
+// import 'core-js/es6/reflect';
+
+
+/** Evergreen browsers require these. **/
+// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
+import 'core-js/es7/reflect';
+
+
+/**
+ * Required to support Web Animations `@angular/platform-browser/animations`.
+ * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
+ **/
+// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
+
+
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone';  // Included with Angular CLI.
+
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts b/web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts
new file mode 100644
index 0000000..1b01809
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/consolelogger.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ConsoleLoggerService } from '../../app/consolelogger.service';
+
+/**
+ * ONOS GUI -- Console Logger Service - Unit Tests
+ */
+describe('ConsoleloggerService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ConsoleLoggerService]
+    });
+  });
+
+  it('should be created', inject([ConsoleLoggerService], (service: ConsoleLoggerService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
new file mode 100644
index 0000000..380a7be
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/detectbrowser.directive.spec.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { DetectBrowserDirective } from '../../app/detectbrowser.directive';
+import { LogService } from '../../app/log.service';
+import { FnService } from '../../app/fw/util/fn.service';
+import { OnosService } from '../../app/onos.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockOnosService extends OnosService {
+    // Override things as necessary
+}
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- Detect Browser Directive - Unit Tests
+ */
+describe('DetectBrowserDirective', () => {
+
+    let onos: MockOnosService;
+    let fs: MockFunctionService;
+    let log: LogService;
+    let ar: ActivatedRoute;
+    let directive: DetectBrowserDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        onos = new MockOnosService(log);
+        fs = new MockFunctionService(ar, log);
+        directive = new DetectBrowserDirective(fs, log, onos);
+    });
+
+    afterEach(() => {
+        onos = null;
+        fs = null;
+        log = null;
+        ar = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/detailspanel.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/detailspanel.service.spec.ts
new file mode 100644
index 0000000..982200b
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/detailspanel.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { DetailsPanelService } from '../../../../app/fw/layer/detailspanel.service';
+
+/**
+ * ONOS GUI -- Layer -- Details Panel Service - Unit Tests
+ */
+describe('DetailsPanelService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [DetailsPanelService]
+    });
+  });
+
+  it('should be created', inject([DetailsPanelService], (service: DetailsPanelService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/dialog.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/dialog.service.spec.ts
new file mode 100644
index 0000000..3035122
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/dialog.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { DialogService } from '../../../../app/fw/layer/dialog.service';
+
+/**
+ * ONOS GUI -- Layer -- Dialog Service - Unit Tests
+ */
+describe('DialogService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [DialogService]
+    });
+  });
+
+  it('should be created', inject([DialogService], (service: DialogService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts
new file mode 100644
index 0000000..5ae266a
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/editabletext.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { EditableTextService } from '../../../../app/fw/layer/editabletext.service';
+
+/**
+ * ONOS GUI -- Layer -- Editable Text Service - Unit Tests
+ */
+describe('EditableTextService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [EditableTextService]
+    });
+  });
+
+  it('should be created', inject([EditableTextService], (service: EditableTextService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/flash.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/flash.service.spec.ts
new file mode 100644
index 0000000..339742b
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/flash.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { FlashService } from '../../../../app/fw/layer/flash.service';
+
+/**
+ * ONOS GUI -- Layer -- Flash Service - Unit Tests
+ */
+describe('FlashService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [FlashService]
+    });
+  });
+
+  it('should be created', inject([FlashService], (service: FlashService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts
new file mode 100644
index 0000000..551f72d
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/loading.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2015-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { LoadingService } from '../../../../app/fw/layer/loading.service';
+
+/**
+ * ONOS GUI -- Layer -- Loading Service - Unit Tests
+ */
+describe('LoadingService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [LoadingService]
+    });
+  });
+
+  it('should be created', inject([LoadingService], (service: LoadingService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/panel.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/panel.service.spec.ts
new file mode 100644
index 0000000..dfa760d
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/panel.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { PanelService } from '../../../../app/fw/layer/panel.service';
+
+/**
+ * ONOS GUI -- Layer -- Panel Service - Unit Tests
+ */
+describe('PanelService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [PanelService]
+    });
+  });
+
+  it('should be created', inject([PanelService], (service: PanelService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts
new file mode 100644
index 0000000..19ce774
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/quickhelp.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { QuickHelpService } from '../../../../app/fw/layer/quickhelp.service';
+
+/**
+ * ONOS GUI -- Layer -- Quick Help Service - Unit Tests
+ */
+describe('QuickHelpService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [QuickHelpService]
+    });
+  });
+
+  it('should be created', inject([QuickHelpService], (service: QuickHelpService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/layer/veil.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/layer/veil.service.spec.ts
new file mode 100644
index 0000000..e99bf61
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/layer/veil.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { VeilService } from '../../../../app/fw/layer/veil.service';
+
+/**
+ * ONOS GUI -- Layer -- Veil Service - Unit Tests
+ */
+describe('VeilService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [VeilService]
+    });
+  });
+
+  it('should be created', inject([VeilService], (service: VeilService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts
new file mode 100644
index 0000000..58eba10
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/mast/mast.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { MastService } from '../../../../app/fw/mast/mast.service';
+
+/**
+ * ONOS GUI -- Masthead Service - Unit Tests
+ */
+describe('MastService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [MastService]
+    });
+  });
+
+  it('should be created', inject([MastService], (service: MastService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/mast/mast/mast.component.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/mast/mast/mast.component.spec.ts
new file mode 100644
index 0000000..94f0f16
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/mast/mast/mast.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MastComponent } from '../../../../../app/fw/mast/mast/mast.component';
+
+/**
+ * ONOS GUI -- Masthead Controller - Unit Tests
+ */
+describe('MastComponent', () => {
+  let component: MastComponent;
+  let fixture: ComponentFixture<MastComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ MastComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MastComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts
new file mode 100644
index 0000000..87df70a
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/nav/nav.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { NavService } from '../../../../app/fw/nav/nav.service';
+
+/**
+ * ONOS GUI -- Util -- Navigation Service - Unit Tests
+ */
+describe('NavService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [NavService]
+    });
+  });
+
+  it('should be created', inject([NavService], (service: NavService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/nav/nav/nav.component.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/nav/nav/nav.component.spec.ts
new file mode 100644
index 0000000..adff327
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/nav/nav/nav.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NavComponent } from '../../../../../app/fw/nav/nav/nav.component';
+
+/**
+ * ONOS GUI -- Util -- Navigation Component - Unit Tests
+ */
+describe('NavComponent', () => {
+  let component: NavComponent;
+  let fixture: ComponentFixture<NavComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ NavComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NavComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts
new file mode 100644
index 0000000..e88c522
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/remote/rest.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { RestService } from '../../../../app/fw/remote/rest.service';
+
+/**
+ * ONOS GUI -- Remote -- REST Service - Unit Tests
+ */
+describe('RestService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [RestService]
+    });
+  });
+
+  it('should be created', inject([RestService], (service: RestService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/remote/urlfn.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/remote/urlfn.service.spec.ts
new file mode 100644
index 0000000..5891260
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/remote/urlfn.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { UrlFnService } from '../../../../app/fw/remote/urlfn.service';
+
+/**
+ * ONOS GUI -- Remote -- General Functions - Unit Tests
+ */
+describe('UrlFnService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [UrlFnService]
+    });
+  });
+
+  it('should be created', inject([UrlFnService], (service: UrlFnService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/remote/websocket.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/remote/websocket.service.spec.ts
new file mode 100644
index 0000000..7f448a8
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/remote/websocket.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { WebSocketService } from '../../../../app/fw/remote/websocket.service';
+
+/**
+ * ONOS GUI -- Remote -- Web Socket Service - Unit Tests
+ */
+describe('WebSocketService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [WebSocketService]
+    });
+  });
+
+  it('should be created', inject([WebSocketService], (service: WebSocketService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/remote/wsock.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/remote/wsock.service.spec.ts
new file mode 100644
index 0000000..0dcfce8
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/remote/wsock.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { WSock } from '../../../../app/fw/remote/wsock.service';
+
+/**
+ * ONOS GUI -- Remote -- WSock Service - Unit Tests
+ */
+describe('WSock', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [WSock]
+    });
+  });
+
+  it('should be created', inject([WSock], (service: WSock) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts
new file mode 100644
index 0000000..3acc8fe
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/geodata.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { GeoDataService } from '../../../../app/fw/svg/geodata.service';
+
+/**
+ * ONOS GUI -- SVG -- GeoData Service - Unit Tests
+ */
+describe('GeoDataService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [GeoDataService]
+    });
+  });
+
+  it('should be created', inject([GeoDataService], (service: GeoDataService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts
new file mode 100644
index 0000000..53ac558
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/glyph.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { GlyphService } from '../../../../app/fw/svg/glyph.service';
+
+/**
+ * ONOS GUI -- SVG -- Glyph Service - Unit Tests
+ */
+describe('GlyphService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [GlyphService]
+    });
+  });
+
+  it('should be created', inject([GlyphService], (service: GlyphService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts
new file mode 100644
index 0000000..de6ddf2
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/glyphdata.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { GlyphDataService } from '../../../../app/fw/svg/glyphdata.service';
+
+/**
+ * ONOS GUI -- SVG -- Glyph Data Service - Unit Tests
+ */
+describe('GlyphDataService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [GlyphDataService]
+    });
+  });
+
+  it('should be created', inject([GlyphDataService], (service: GlyphDataService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/icon.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/icon.directive.spec.ts
new file mode 100644
index 0000000..f00b8ca
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/icon.directive.spec.ts
@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { IconDirective } from '../../../../app/fw/svg/icon.directive';
+import { LogService } from '../../../../app/log.service';
+import { IconService } from '../../../../app/fw/svg/icon.service';
+import { GlyphService } from '../../../../app/fw/svg/glyph.service';
+import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
+import { FnService } from '../../../../app/fw//util/fn.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockGlyphService extends GlyphService {
+    // Override things as necessary
+}
+
+class MockSvgUtilService extends SvgUtilService {
+    // Override things as necessary
+}
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- SVG -- Icon Directive - Unit Tests
+ */
+describe('IconDirective', () => {
+    let ar: ActivatedRoute;
+    let log: LogService;
+    let fs: MockFunctionService;
+    let gs: GlyphService;
+    let is: IconService;
+    let sus: SvgUtilService;
+    let directive: IconDirective;
+
+    beforeEach(() => {
+        ar = new ActivatedRoute();
+        log = new LogService();
+        fs = new MockFunctionService(ar, log);
+        sus = new MockSvgUtilService(fs, log);
+        gs = new GlyphService(log);
+        is = new IconService(gs, log, sus);
+        directive = new IconDirective(is, log);
+    });
+
+    afterEach(() => {
+        is = null;
+        log = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts
new file mode 100644
index 0000000..47bef85
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/icon.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { IconService } from '../../../../app/fw/svg/icon.service';
+
+/**
+ * ONOS GUI -- SVG -- Icon Service - Unit Tests
+ */
+describe('IconService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [IconService]
+    });
+  });
+
+  it('should be created', inject([IconService], (service: IconService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts
new file mode 100644
index 0000000..84cd80a
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/icon/icon.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { IconComponent } from '../../../../../app/fw/svg/icon/icon.component';
+
+describe('IconComponent', () => {
+  let component: IconComponent;
+  let fixture: ComponentFixture<IconComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ IconComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(IconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts
new file mode 100644
index 0000000..d5c3cd1
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/map.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { MapService } from '../../../../app/fw/svg/map.service';
+
+/**
+ * ONOS GUI -- SVG -- Map Service - Unit Tests
+ */
+describe('MapService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [MapService]
+    });
+  });
+
+  it('should be created', inject([MapService], (service: MapService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts
new file mode 100644
index 0000000..8996b4f
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/sprite.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SpriteService } from '../../../../app/fw/svg/sprite.service';
+
+/**
+ * ONOS GUI -- SVG -- Sprite Service - Unit Tests
+ */
+describe('SpriteService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [SpriteService]
+    });
+  });
+
+  it('should be created', inject([SpriteService], (service: SpriteService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts
new file mode 100644
index 0000000..1d14006
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/spritedata.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SpriteDataService } from '../../../../app/fw/svg/spritedata.service';
+
+/**
+ * ONOS GUI -- SVG -- Sprite Data Service - Unit Tests
+ */
+describe('SpriteDataService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [SpriteDataService]
+    });
+  });
+
+  it('should be created', inject([SpriteDataService], (service: SpriteDataService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts
new file mode 100644
index 0000000..8d4a21e
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/svgutil.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
+
+/**
+ * ONOS GUI -- SVG -- Svg Util Service - Unit Tests
+ */
+describe('SvgUtilService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [SvgUtilService]
+    });
+  });
+
+  it('should be created', inject([SvgUtilService], (service: SvgUtilService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts
new file mode 100644
index 0000000..4016500
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/svg/zoom.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ZoomService } from '../../../../app/fw/svg/zoom.service';
+
+/**
+ * ONOS GUI -- SVG -- Zoom Service - Unit Tests
+ */
+describe('ZoomService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ZoomService]
+    });
+  });
+
+  it('should be created', inject([ZoomService], (service: ZoomService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts
new file mode 100644
index 0000000..157e2bc
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/ee.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2016-present Open Networking Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { EeService } from '../../../../app/fw/util/ee.service';
+
+/**
+ * ONOS GUI -- Util -- EE functions - Unit Tests
+ */
+describe('EeService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [EeService]
+    });
+  });
+
+  it('should be created', inject([EeService], (service: EeService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/fn.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/fn.service.spec.ts
new file mode 100644
index 0000000..c07e858
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/fn.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { FnService } from '../../../../app/fw/util/fn.service';
+
+/**
+ * ONOS GUI -- Util -- General Purpose Functions - Unit Tests
+ */
+describe('FnService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [FnService]
+    });
+  });
+
+  it('should be created', inject([FnService], (service: FnService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts
new file mode 100644
index 0000000..c277344
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/key.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { KeyService } from '../../../../app/fw/util/key.service';
+
+/**
+ * ONOS GUI -- Key Handler Service - Unit Tests
+ */
+describe('KeyService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [KeyService]
+    });
+  });
+
+  it('should be created', inject([KeyService], (service: KeyService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts
new file mode 100644
index 0000000..fc8c4fc
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/lion.service.spec.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { LionService } from '../../../../app/fw/util/lion.service';
+
+/**
+ * ONOS GUI -- Lion -- Localization Utilities - Unit Tests
+ */
+describe('LionService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [LionService]
+    });
+  });
+
+  it('should be created', inject([LionService], (service: LionService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts
new file mode 100644
index 0000000..b27662f
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/prefs.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { PrefsService } from '../../../../app/fw/util/prefs.service';
+
+/**
+ ONOS GUI -- Util -- User Preference Service - Unit Tests
+ */
+describe('PrefsService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [PrefsService]
+    });
+  });
+
+  it('should be created', inject([PrefsService], (service: PrefsService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts
new file mode 100644
index 0000000..969ad69
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/random.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { RandomService } from '../../../../app/fw/util/random.service';
+
+/**
+ * ONOS GUI -- Random -- Encapsulated randomness - Unit Tests
+ */
+describe('RandomService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [RandomService]
+    });
+  });
+
+  it('should be created', inject([RandomService], (service: RandomService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts
new file mode 100644
index 0000000..b5a1ff8
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/util/theme.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ThemeService } from '../../../../app/fw/util/theme.service';
+
+/**
+ * ONOS GUI -- Util -- Theme Service - Unit Tests
+ */
+describe('ThemeService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ThemeService]
+    });
+  });
+
+  it('should be created', inject([ThemeService], (service: ThemeService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts
new file mode 100644
index 0000000..d2bb5b9
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/button.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ButtonService } from '../../../../app/fw/widget/button.service';
+
+/**
+ * ONOS GUI -- Widget -- Button Service - Unit Tests
+ */
+describe('ButtonService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ButtonService]
+    });
+  });
+
+  it('should be created', inject([ButtonService], (service: ButtonService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts
new file mode 100644
index 0000000..6840fe3
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/chartbuilder.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ChartBuilderService } from '../../../../app/fw/widget/chartbuilder.service';
+
+/**
+ * ONOS GUI -- Widget -- Chart Builder Service - Unit Tests
+ */
+describe('ChartBuilderService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ChartBuilderService]
+    });
+  });
+
+  it('should be created', inject([ChartBuilderService], (service: ChartBuilderService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/flashchanges.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/flashchanges.directive.spec.ts
new file mode 100644
index 0000000..f301cfc
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/flashchanges.directive.spec.ts
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { FlashChangesDirective } from '../../../../app/fw/widget/flashchanges.directive';
+
+import { LogService } from '../../../../app/log.service';
+import { FnService } from '../../../../app/fw/util/fn.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- Widget -- Table Flash Changes Directive - Unit Tests
+ */
+describe('FlashChangesDirective', () => {
+    let fs: MockFunctionService;
+    let log: LogService;
+    let ar: ActivatedRoute;
+    let directive: FlashChangesDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        fs = new MockFunctionService(ar, log);
+        directive = new FlashChangesDirective(fs, log);
+    });
+
+    afterEach(() => {
+        fs = null;
+        log = null;
+        ar = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts
new file mode 100644
index 0000000..0285417
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/list.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ListService } from '../../../../app/fw/widget/list.service';
+
+/**
+ * ONOS GUI -- Widget -- List Service - Unit Tests
+ */
+describe('ListService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ListService]
+    });
+  });
+
+  it('should be created', inject([ListService], (service: ListService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts
new file mode 100644
index 0000000..7d15dfc
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/sortableheader.directive.spec.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { SortableHeaderDirective } from '../../../../app/fw/widget/sortableheader.directive';
+import { IconService } from '../../../../app/fw/svg/icon.service';
+import { GlyphService } from '../../../../app/fw/svg/glyph.service';
+import { SvgUtilService } from '../../../../app/fw/svg/svgutil.service';
+import { LogService } from '../../../../app/log.service';
+import { FnService } from '../../../../app/fw/util/fn.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockGlyphService extends GlyphService {
+    // Override things as necessary
+}
+
+class MockSvgUtilService extends SvgUtilService {
+    // Override things as necessary
+}
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- Widget -- Table Sortable Header Directive - Unit Tests
+ */
+describe('SortableHeaderDirective', () => {
+    let gs: MockGlyphService;
+    let sus: MockSvgUtilService;
+    let icon: IconService;
+    let log: LogService;
+    let fs: MockFunctionService;
+    let ar: ActivatedRoute;
+    let directive: SortableHeaderDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        fs = new MockFunctionService(ar, log);
+        gs = new MockGlyphService(log);
+        sus = new MockSvgUtilService(fs, log);
+        icon = new IconService(gs, log, sus);
+        directive = new SortableHeaderDirective(icon, log);
+    });
+
+    afterEach(() => {
+        log = null;
+        icon = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tablebuilder.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tablebuilder.service.spec.ts
new file mode 100644
index 0000000..fb4aac7
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/tablebuilder.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { TableBuilderService } from '../../../../app/fw/widget/tablebuilder.service';
+
+/*
+ ONOS GUI -- Widget -- Table Builder Service - Unit Tests
+ */
+describe('TableBuilderService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [TableBuilderService]
+    });
+  });
+
+  it('should be created', inject([TableBuilderService], (service: TableBuilderService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tabledetail.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tabledetail.service.spec.ts
new file mode 100644
index 0000000..5df608c
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/tabledetail.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { TableDetailService } from '../../../../app/fw/widget/tabledetail.service';
+
+/**
+ * ONOS GUI -- Widget -- Table Detail Service - Unit Tests
+ */
+describe('TableDetailService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [TableDetailService]
+    });
+  });
+
+  it('should be created', inject([TableDetailService], (service: TableDetailService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts
new file mode 100644
index 0000000..a8241ea
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/tableresize.directive.spec.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TableResizeDirective } from '../../../../app/fw/widget/tableresize.directive';
+import { LogService } from '../../../../app/log.service';
+import { FnService } from '../../../../app/fw/util/fn.service';
+import { MastService } from '../../../../app/fw/mast/mast.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- Widget -- Table Resize Directive - Unit Tests
+ */
+describe('TableResizeDirective', () => {
+
+    let fs: MockFunctionService;
+    let log: LogService;
+    let ar: ActivatedRoute;
+    let ms: MastService;
+    let directive: TableResizeDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        fs = new MockFunctionService(ar, log);
+        ms = new MastService(fs, log);
+        directive = new TableResizeDirective(fs, log, ms);
+    });
+
+    afterEach(() => {
+        fs = null;
+        log = null;
+        ar = null;
+        ms = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/toolbar.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/toolbar.service.spec.ts
new file mode 100644
index 0000000..467462a
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/toolbar.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ToolbarService } from '../../../../app/fw/widget/toolbar.service';
+
+/**
+ * ONOS GUI -- Widget -- Toolbar Service - Unit Tests
+ */
+describe('ToolbarService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ToolbarService]
+    });
+  });
+
+  it('should be created', inject([ToolbarService], (service: ToolbarService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.directive.spec.ts
new file mode 100644
index 0000000..f8f41da
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.directive.spec.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TooltipDirective } from '../../../../app/fw/widget/tooltip.directive';
+import { LogService } from '../../../../app/log.service';
+import { FnService } from '../../../../app/fw/util/fn.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+/**
+ * ONOS GUI -- Widget -- Tooltip Directive - Unit Tests
+ */
+describe('TooltipDirective', () => {
+    let fs: MockFunctionService;
+    let log: LogService;
+    let ar: ActivatedRoute;
+    let directive: TooltipDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        fs = new MockFunctionService(ar, log);
+        directive = new TooltipDirective(fs, log);
+    });
+
+    afterEach(() => {
+        fs = null;
+        log = null;
+        ar = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.service.spec.ts b/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.service.spec.ts
new file mode 100644
index 0000000..651ef5d
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/fw/widget/tooltip.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { TooltipService } from '../../../../app/fw/widget/tooltip.service';
+
+/**
+ * ONOS GUI -- Widget -- Tooltip Service - Unit Tests
+ */
+describe('TooltipService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [TooltipService]
+    });
+  });
+
+  it('should be created', inject([TooltipService], (service: TooltipService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/log.service.spec.ts b/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
new file mode 100644
index 0000000..5307028
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/log.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { LogService } from '../../app/log.service';
+
+/**
+ * ONOS GUI -- Log Service - Unit Tests
+ */
+describe('LogService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [LogService]
+    });
+  });
+
+  it('should be created', inject([LogService], (service: LogService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts b/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts
new file mode 100644
index 0000000..1808eb6
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/onos.component.spec.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, async } from '@angular/core/testing';
+import { OnosComponent } from '../../app/onos.component';
+
+/**
+ * ONOS GUI -- Onos Component - Unit Tests
+ */
+describe('OnosComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [
+        OnosComponent
+      ],
+    }).compileComponents();
+  }));
+  it('should create the app', async(() => {
+    const fixture = TestBed.createComponent(OnosComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app).toBeTruthy();
+  }));
+  it(`should have as title 'onos'`, async(() => {
+    const fixture = TestBed.createComponent(OnosComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app.title).toEqual('onos');
+  }));
+  it('should render title in a h1 tag', async(() => {
+    const fixture = TestBed.createComponent(OnosComponent);
+    fixture.detectChanges();
+    const compiled = fixture.debugElement.nativeElement;
+    expect(compiled.querySelector('h1').textContent).toContain('Welcome to onos!');
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts b/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
new file mode 100644
index 0000000..867f14a
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/onos.service.spec.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TestBed, inject } from '@angular/core/testing';
+
+import { OnosService } from '../../app/onos.service';
+
+/**
+ * ONOS GUI -- Onos Service - Unit Tests
+ */
+describe('OnosService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [OnosService]
+    });
+  });
+
+  it('should be created', inject([OnosService], (service: OnosService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/web/gui2/src/main/webapp/tests/app/view/apps/apps.component.spec.ts b/web/gui2/src/main/webapp/tests/app/view/apps/apps.component.spec.ts
new file mode 100644
index 0000000..f6ca0f8
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/view/apps/apps.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AppsComponent } from '../../../../app/view/apps/apps.component';
+
+describe('AppsComponent', () => {
+  let component: AppsComponent;
+  let fixture: ComponentFixture<AppsComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AppsComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AppsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/view/apps/triggerform.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/view/apps/triggerform.directive.spec.ts
new file mode 100644
index 0000000..6ec3d73
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/view/apps/triggerform.directive.spec.ts
@@ -0,0 +1,8 @@
+import { TriggerFormDirective } from '../../../../app/view/apps/triggerform.directive';
+
+describe('TriggerFormDirective', () => {
+  it('should create an instance', () => {
+    const directive = new TriggerFormDirective();
+    expect(directive).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/view/device/device.component.spec.ts b/web/gui2/src/main/webapp/tests/app/view/device/device.component.spec.ts
new file mode 100644
index 0000000..e4e06a1
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/view/device/device.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DeviceComponent } from '../../../../app/view/device/device.component';
+
+/**
+ * ONOS GUI -- Device View Module - Unit Tests
+ */
+describe('DeviceComponent', () => {
+  let component: DeviceComponent;
+  let fixture: ComponentFixture<DeviceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ DeviceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(DeviceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/web/gui2/src/main/webapp/tests/app/view/device/devicedetailspanel.directive.spec.ts b/web/gui2/src/main/webapp/tests/app/view/device/devicedetailspanel.directive.spec.ts
new file mode 100644
index 0000000..bbf3062
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/app/view/device/devicedetailspanel.directive.spec.ts
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { DeviceDetailsPanelDirective } from '../../../../app/view/device/devicedetailspanel.directive';
+import { KeyService } from '../../../../app/fw/util/key.service';
+import { LogService } from '../../../../app/log.service';
+import { FnService } from '../../../../app/fw/util/fn.service';
+import { ActivatedRoute, Router} from '@angular/router';
+
+class MockFunctionService extends FnService {
+    // Override things as necessary
+}
+
+class MockKeyService extends KeyService {
+    // Override things as necessary
+}
+/**
+ * ONOS GUI -- Device View Module - Unit Tests
+ */
+describe('DeviceDetailsPanelDirective', () => {
+    let ar: ActivatedRoute;
+    let log: LogService;
+    let ks: KeyService;
+    let fs: MockFunctionService;
+    let window: Window
+    let directive: DeviceDetailsPanelDirective;
+
+    beforeEach(() => {
+        log = new LogService();
+        ar = new ActivatedRoute();
+        fs = new MockFunctionService(ar, log);
+        ks = new MockKeyService(fs, log);
+        directive = new DeviceDetailsPanelDirective(ks, log, window);
+    });
+
+    afterEach(() => {
+        fs = null;
+        ks = null;
+        log = null;
+        ar = null;
+        directive = null;
+    });
+
+    it('should create an instance', () => {
+        expect(directive).toBeTruthy();
+    });
+});
diff --git a/web/gui2/src/main/webapp/tests/test.ts b/web/gui2/src/main/webapp/tests/test.ts
new file mode 100644
index 0000000..1631789
--- /dev/null
+++ b/web/gui2/src/main/webapp/tests/test.ts
@@ -0,0 +1,20 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/web/gui2/src/main/webapp/tsconfig.app.json b/web/gui2/src/main/webapp/tsconfig.app.json
new file mode 100644
index 0000000..d470edb
--- /dev/null
+++ b/web/gui2/src/main/webapp/tsconfig.app.json
@@ -0,0 +1,13 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "baseUrl": "./",
+    "module": "es2015",
+    "types": []
+  },
+  "exclude": [
+    "tests/test.ts",
+    "**/*.spec.ts"
+  ]
+}
diff --git a/web/gui2/src/main/webapp/tsconfig.spec.json b/web/gui2/src/main/webapp/tsconfig.spec.json
new file mode 100644
index 0000000..a322b0e
--- /dev/null
+++ b/web/gui2/src/main/webapp/tsconfig.spec.json
@@ -0,0 +1,20 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/spec",
+    "baseUrl": "./",
+    "module": "commonjs",
+    "types": [
+      "jasmine",
+      "node"
+    ]
+  },
+  "files": [
+    "tests/test.ts",
+    "polyfills.ts"
+  ],
+  "include": [
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}
diff --git a/web/gui2/src/main/webapp/typings.d.ts b/web/gui2/src/main/webapp/typings.d.ts
new file mode 100644
index 0000000..ef5c7bd
--- /dev/null
+++ b/web/gui2/src/main/webapp/typings.d.ts
@@ -0,0 +1,5 @@
+/* SystemJS module definition */
+declare var module: NodeModule;
+interface NodeModule {
+  id: string;
+}