GUI - Cleanup of old files.

Change-Id: I2fd30f32d15ecb0b97ee7f380523ebb8513a6a01
diff --git a/web/gui/src/main/webapp/OLD/geometry.js b/web/gui/src/main/webapp/OLD/geometry.js
new file mode 100644
index 0000000..5ede643
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/geometry.js
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/*
+ Geometry library - based on work by Mike Bostock.
+ */
+
+(function() {
+
+    if (typeof geo == 'undefined') {
+        geo = {};
+    }
+
+    var tolerance = 1e-10;
+
+    function eq(a, b) {
+        return (Math.abs(a - b) < tolerance);
+    }
+
+    function gt(a, b) {
+        return (a - b > -tolerance);
+    }
+
+    function lt(a, b) {
+        return gt(b, a);
+    }
+
+    geo.eq = eq;
+    geo.gt = gt;
+    geo.lt = lt;
+
+    geo.LineSegment = function(x1, y1, x2, y2) {
+        this.x1 = x1;
+        this.y1 = y1;
+        this.x2 = x2;
+        this.y2 = y2;
+
+        // Ax + By = C
+        this.a = y2 - y1;
+        this.b = x1 - x2;
+        this.c = x1 * this.a + y1 * this.b;
+
+        if (eq(this.a, 0) && eq(this.b, 0)) {
+            throw new Error(
+                'Cannot construct a LineSegment with two equal endpoints.');
+        }
+    };
+
+    geo.LineSegment.prototype.intersect = function(that) {
+        var d = (this.x1 - this.x2) * (that.y1 - that.y2) -
+            (this.y1 - this.y2) * (that.x1 - that.x2);
+
+        if (eq(d, 0)) {
+            // The two lines are parallel or very close.
+            return {
+                x : NaN,
+                y : NaN
+            };
+        }
+
+        var t1  = this.x1 * this.y2 - this.y1 * this.x2,
+            t2  = that.x1 * that.y2 - that.y1 * that.x2,
+            x   = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d,
+            y   = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d,
+            in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) &&
+                gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))),
+            in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) &&
+                gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2)));
+
+        return {
+            x   : x,
+            y   : y,
+            in1 : in1,
+            in2 : in2
+        };
+    };
+
+    geo.LineSegment.prototype.x = function(y) {
+        // x = (C - By) / a;
+        if (this.a) {
+            return (this.c - this.b * y) / this.a;
+        } else {
+            // a == 0 -> horizontal line
+            return NaN;
+        }
+    };
+
+    geo.LineSegment.prototype.y = function(x) {
+        // y = (C - Ax) / b;
+        if (this.b) {
+            return (this.c - this.a * x) / this.b;
+        } else {
+            // b == 0 -> vertical line
+            return NaN;
+        }
+    };
+
+    geo.LineSegment.prototype.length = function() {
+        return Math.sqrt(
+                (this.y2 - this.y1) * (this.y2 - this.y1) +
+                (this.x2 - this.x1) * (this.x2 - this.x1));
+    };
+
+    geo.LineSegment.prototype.offset = function(x, y) {
+        return new geo.LineSegment(
+                this.x1 + x, this.y1 + y,
+                this.x2 + x, this.y2 + y);
+    };
+
+})();
diff --git a/web/gui/src/main/webapp/OLD/index.html b/web/gui/src/main/webapp/OLD/index.html
new file mode 100644
index 0000000..7fecd38
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/index.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--
+  ~ Copyright 2014 Open Networking Laboratory
+  ~
+  ~ 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 UI - single page web app
+
+  @author Simon Hunt
+  -->
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>ONOS GUI</title>
+
+    <!--TODO: use the minified version of d3, once debugging is complete -->
+    <script src="../libs/d3.js"></script>
+    <script src="../libs/jquery-2.1.1.min.js"></script>
+
+    <link rel="stylesheet" href="../base.css">
+    <link rel="stylesheet" href="onos.css">
+
+    <script src="../geometry.js"></script>
+    <script src="onos.js"></script>
+
+</head>
+<body>
+    <div id="frame">
+        <div id="mast">
+            <img id="logo" src="../img/onos-logo.png">
+            <span class="title">Open Network Operating System</span>
+            <span id="displayModes" class="right">
+                <span id="showAll" class="radio active">All Layers</span>
+                <span id="showPkt" class="radio">Packet Only</span>
+                <span id="showOpt" class="radio">Optical Only</span>
+            </span>
+        </div>
+        <div id="view">
+            <!-- NOTE: svg layer injected here -->
+        </div>
+        <div id="flyout"></div>
+    </div>
+
+    <!-- Initialize the UI...-->
+    <script type="text/javascript">
+        var ONOS = $.onos({note: "config, if needed"});
+    </script>
+
+    <!-- include module files-->
+    <!-- + mast.js-->
+    <!-- + nav.js-->
+    <!-- + .... application views-->
+
+    <!-- for now, we are just bootstrapping the network visualization-->
+    <script src="network.js" type="text/javascript"></script>
+
+    <!-- finally, build the UI-->
+    <script type="text/javascript">
+        $(ONOS.buildUi);
+    </script>
+
+</body>
+</html>
diff --git a/web/gui/src/main/webapp/OLD/json/network.json b/web/gui/src/main/webapp/OLD/json/network.json
new file mode 100644
index 0000000..b2f6d3a
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/network.json
@@ -0,0 +1,181 @@
+{
+    "meta": {
+        "comments": [
+            "This is sample data for developing the ONOS UI (network view)",
+            " in a standalone mode (no server required).",
+            " Eventually, we will wire this up to live data",
+            " from the server, via a websocket.",
+            "",
+            "Note that this is just a first-draft of the data --",
+            " additional fields will be added when they are needed."
+        ],
+        "otherMetaData": "can go here..."
+    },
+    "devices": [
+        {
+            "id": "of:0000000000000001",
+            "labels": ["00:00:00:00:00:00:00:01", "SFO-W10", "opt-1"],
+            "type": "roadm"
+        },
+        {
+            "id": "of:0000000000000002",
+            "labels": ["00:00:00:00:00:00:00:02", "SJC-W10", "opt-2"],
+            "type": "roadm"
+        },
+        {
+            "id": "of:0000000000000003",
+            "labels": ["00:00:00:00:00:00:00:03", "LAX-W10", "opt-3"],
+            "type": "roadm"
+        },
+        {
+            "id": "of:0000000000000004",
+            "labels": ["00:00:00:00:00:00:00:04", "SDG-W10", "opt-4"],
+            "type": "roadm"
+        },
+        {
+            "id": "of:0000000000000011",
+            "labels": ["00:00:00:00:00:00:00:11", "SFO-pkt", "pkt-11"],
+            "type": "switch"
+        },
+        {
+            "id": "of:0000000000000012",
+            "labels": ["00:00:00:00:00:00:00:12", "SJC-pkt", "pkt-12"],
+            "type": "switch"
+        },
+        {
+            "id": "of:0000000000000013",
+            "labels": ["00:00:00:00:00:00:00:13", "LAX-pkt", "pkt-13"],
+            "type": "switch"
+        }
+    ],
+    "linkNotes": [
+        "even though we have 'directionality' (src/dst), each link is",
+        " considered to be bi-directional. Note that links between hosts",
+        " and edge switches are inferred from host information, and not",
+        " explicitly represented here."
+    ],
+    "links": [
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000002",
+            "type": "optical",
+            "srcPort": 1,
+            "dstPort": 2,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000003",
+            "type": "optical",
+            "srcPort": 2,
+            "dstPort": 5,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "srcPort": 3,
+            "dstPort": 2,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000002",
+            "dst": "of:0000000000000003",
+            "type": "optical",
+            "srcPort": 3,
+            "dstPort": 4,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000002",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "srcPort": 4,
+            "dstPort": 1,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000003",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "srcPort": 3,
+            "dstPort": 3,
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000013",
+            "dst": "of:0000000000000003",
+            "type": "direct",
+            "srcPort": 1,
+            "dstPort": 7,
+            "linkWidth": 1.0
+        },
+        {
+            "src": "of:0000000000000012",
+            "dst": "of:0000000000000002",
+            "type": "direct",
+            "srcPort": 1,
+            "dstPort": 9,
+            "linkWidth": 1.0
+        },
+        {
+            "src": "of:0000000000000011",
+            "dst": "of:0000000000000001",
+            "type": "direct",
+            "srcPort": 1,
+            "dstPort": 6,
+            "linkWidth": 1.0
+        }
+    ],
+    "hosts": [
+        {
+            "id": "00:60:d3:00:11:01/7",
+            "labels": ["00:60:d3:00:11:01/7", "Host-11-A"],
+            "cp" : {
+                "device": "of:0000000000000011",
+                "port": 6
+            }
+        },
+        {
+            "id": "00:60:d3:00:11:02/7",
+            "labels": ["00:60:d3:00:11:02/7", "Host-11-B"],
+            "cp" : {
+                "device": "of:0000000000000011",
+                "port": 8
+            }
+        },
+        {
+            "id": "00:60:d3:00:12:01/4",
+            "labels": ["00:60:d3:00:12:01/4", "Host-12-C"],
+            "cp" : {
+                "device": "of:0000000000000012",
+                "port": 12
+            }
+        },
+        {
+            "id": "00:60:d3:00:12:02/4",
+            "labels": ["00:60:d3:00:12:02/4", "Host-12-D"],
+            "cp" : {
+                "device": "of:0000000000000012",
+                "port": 13
+            }
+        },
+        {
+            "id": "00:60:d3:00:13:01/19",
+            "labels": ["00:60:d3:00:13:01/19", "Host-13-E"],
+            "cp" : {
+                "device": "of:0000000000000013",
+                "port": 7
+            }
+        },
+        {
+            "id": "00:60:d3:00:13:02/19",
+            "labels": ["00:60:d3:00:13:02/19", "Host-13-F"],
+            "cp" : {
+                "device": "of:0000000000000013",
+                "port": 8
+            }
+        }
+    ]
+}
diff --git a/web/gui/src/main/webapp/OLD/json/network2.json b/web/gui/src/main/webapp/OLD/json/network2.json
new file mode 100644
index 0000000..24f1e6c
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/network2.json
@@ -0,0 +1,378 @@
+{
+    "devices": [
+        {
+            "id": "of:0000ffffffffff08",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff08",
+                "FF:FF:FF:FF:FF:08",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff03",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff03",
+                "FF:FF:FF:FF:FF:03",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff02",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff02",
+                "FF:FF:FF:FF:FF:02",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff0003",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff0003",
+                "FF:FF:FF:FF:00:03",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff07",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff07",
+                "FF:FF:FF:FF:FF:07",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff06",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff06",
+                "FF:FF:FF:FF:FF:06",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff0007",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff0007",
+                "FF:FF:FF:FF:00:07",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff05",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff05",
+                "FF:FF:FF:FF:FF:05",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff0009",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff0009",
+                "FF:FF:FF:FF:00:09",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff04",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff04",
+                "FF:FF:FF:FF:FF:04",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff000A",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff000A",
+                "FF:FF:FF:FF:00:0A",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff0001",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff0001",
+                "FF:FF:FF:FF:00:01",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff01",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff01",
+                "FF:FF:FF:FF:FF:01",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffff0004",
+            "type": "switch",
+            "online": false,
+            "labels": [
+                "0000ffffffff0004",
+                "FF:FF:FF:FF:00:04",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff0A",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff0A",
+                "FF:FF:FF:FF:FF:0A",
+                "?"
+            ]
+        },
+        {
+            "id": "of:0000ffffffffff09",
+            "type": "roadm",
+            "online": false,
+            "labels": [
+                "0000ffffffffff09",
+                "FF:FF:FF:FF:FF:09",
+                "?"
+            ]
+        }
+    ],
+    "links": [
+        {
+            "src": "of:0000ffffffffff02",
+            "srcPort": "20",
+            "dst": "of:0000ffffffffff05",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffff000A",
+            "srcPort": "2",
+            "dst": "of:0000ffffffffff0A",
+            "dstPort": "1",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff03",
+            "srcPort": "10",
+            "dst": "of:0000ffffffffff02",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff07",
+            "srcPort": "21",
+            "dst": "of:0000ffffffffff05",
+            "dstPort": "20",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffff0001",
+            "srcPort": "2",
+            "dst": "of:0000ffffffffff01",
+            "dstPort": "1",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff09",
+            "srcPort": "20",
+            "dst": "of:0000ffffffffff0A",
+            "dstPort": "20",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff06",
+            "srcPort": "20",
+            "dst": "of:0000ffffffffff05",
+            "dstPort": "30",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff07",
+            "srcPort": "30",
+            "dst": "of:0000ffffffffff08",
+            "dstPort": "20",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff03",
+            "srcPort": "20",
+            "dst": "of:0000ffffffffff06",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff02",
+            "srcPort": "10",
+            "dst": "of:0000ffffffffff01",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff09",
+            "srcPort": "1",
+            "dst": "of:0000ffffffff0009",
+            "dstPort": "2",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff03",
+            "srcPort": "30",
+            "dst": "of:0000ffffffffff04",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff07",
+            "srcPort": "20",
+            "dst": "of:0000ffffffffff09",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff0A",
+            "srcPort": "10",
+            "dst": "of:0000ffffffffff08",
+            "dstPort": "30",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffff0004",
+            "srcPort": "2",
+            "dst": "of:0000ffffffffff04",
+            "dstPort": "1",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff07",
+            "srcPort": "1",
+            "dst": "of:0000ffffffff0007",
+            "dstPort": "2",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffff0003",
+            "srcPort": "2",
+            "dst": "of:0000ffffffffff03",
+            "dstPort": "1",
+            "type": "optical",
+            "linkWidth": 2
+        },
+        {
+            "src": "of:0000ffffffffff06",
+            "srcPort": "30",
+            "dst": "of:0000ffffffffff08",
+            "dstPort": "10",
+            "type": "optical",
+            "linkWidth": 2
+        }
+    ],
+    "hosts": [
+        {
+            "id": "00:00:00:00:00:03/-1",
+            "cp": {
+                "device": "of:0000ffffffff0003",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.3",
+                "00:00:00:00:00:03"
+            ]
+        },
+        {
+            "id": "00:00:00:00:00:04/-1",
+            "cp": {
+                "device": "of:0000ffffffff0004",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.4",
+                "00:00:00:00:00:04"
+            ]
+        },
+        {
+            "id": "00:00:00:00:00:0A/-1",
+            "cp": {
+                "device": "of:0000ffffffff000A",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.10",
+                "00:00:00:00:00:0A"
+            ]
+        },
+        {
+            "id": "00:00:00:00:00:09/-1",
+            "cp": {
+                "device": "of:0000ffffffff0009",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.9",
+                "00:00:00:00:00:09"
+            ]
+        },
+        {
+            "id": "00:00:00:00:00:07/-1",
+            "cp": {
+                "device": "of:0000ffffffff0007",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.7",
+                "00:00:00:00:00:07"
+            ]
+        },
+        {
+            "id": "00:00:00:00:00:01/-1",
+            "cp": {
+                "device": "of:0000ffffffff0001",
+                "port": 1
+            },
+            "labels": [
+                "10.0.0.1",
+                "00:00:00:00:00:01"
+            ]
+        }
+    ]
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000001.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000001.json
new file mode 100644
index 0000000..1f5c8e9
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000001.json
@@ -0,0 +1,18 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000001",
+    "type": "roadm",
+    "propOrder": [ "name", "type", "-", "dpid", "latitude", "longitude", "allowed" ],
+    "location": {
+        "type": "latlng",
+        "lat": 37.6,
+        "lng": 122.3
+    },
+    "props": {
+        "allowed": true,
+        "latitude": 37.6,
+        "longitude": 122.3,
+        "name": "SFO-W10",
+        "dpid": "00:00:00:00:00:00:00:01"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000002.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000002.json
new file mode 100644
index 0000000..87fd1f2
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000002.json
@@ -0,0 +1,19 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000002",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+    "location": {
+        "type": "latlng",
+        "lat": 37.6,
+        "lng": 122.3
+    },
+    "props": {
+        "allowed": true,
+        "latitude": 37.3,
+        "longitude": 121.9,
+        "name": "SJC-W10",
+        "dpid": "00:00:00:00:00:00:00:02",
+        "type": "Roadm"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000003.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000003.json
new file mode 100644
index 0000000..1315961
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000003.json
@@ -0,0 +1,19 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000003",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+    "location": {
+        "type": "latlng",
+        "lat": 33.9,
+        "lng": 118.4
+    },
+    "props": {
+        "allowed": true,
+        "latitude": 33.9,
+        "longitude": 118.4,
+        "name": "LAX-W10",
+        "dpid": "00:00:00:00:00:00:00:03",
+        "type": "Roadm"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000004.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000004.json
new file mode 100644
index 0000000..ba243baf
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000004.json
@@ -0,0 +1,19 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000004",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
+    "location": {
+        "type": "latlng",
+        "lat": 32.8,
+        "lng": 117.1
+    },
+    "props": {
+        "allowed": true,
+        "latitude": 32.8,
+        "longitude": 117.1,
+        "name": "SDG-W10",
+        "dpid": "00:00:00:00:00:00:00:04",
+        "type": "Roadm"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000011.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000011.json
new file mode 100644
index 0000000..5792dab
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000011.json
@@ -0,0 +1,12 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000011",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "optLink" ],
+    "props": {
+        "name": "SFO-pkt",
+        "dpid": "00:00:00:00:00:00:00:11",
+        "type": "SwitchX",
+        "optLink": "SFO-W10"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000012.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000012.json
new file mode 100644
index 0000000..b65163e
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000012.json
@@ -0,0 +1,12 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000012",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "optLink" ],
+    "props": {
+        "name": "SJC-pkt",
+        "dpid": "00:00:00:00:00:00:00:12",
+        "type": "SwitchX",
+        "optLink": "SJC-W10"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000000000000013.json b/web/gui/src/main/webapp/OLD/json/of_0000000000000013.json
new file mode 100644
index 0000000..ba96b07
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000000000000013.json
@@ -0,0 +1,12 @@
+{
+    "comment": "sample device properties",
+    "id": "of:0000000000000013",
+    "type": "switch",
+    "propOrder": [ "name", "type", "dpid", "optLink" ],
+    "props": {
+        "name": "LAX-pkt",
+        "dpid": "00:00:00:00:00:00:00:13",
+        "type": "SwitchX",
+        "optLink": "LAX-W10"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0007.json b/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0007.json
new file mode 100644
index 0000000..b1d7de6
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0007.json
@@ -0,0 +1,25 @@
+{
+    "id": "of:0000ffffffff0007",
+    "type": "switch",
+    "propOrder": [
+        "Name",
+        "Vendor",
+        "H/W Version",
+        "S/W Version",
+        "S/W Version",
+        "-",
+        "Latitude",
+        "Longitude",
+        "Ports"
+    ],
+    "props": {
+        "Name": null,
+        "Vendor": "Linc",
+        "H/W Version": "PK",
+        "S/W Version": "?",
+        "-": "",
+        "Latitude": "41.8",
+        "Longitude": "120.1",
+        "Ports": "2"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0009.json b/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0009.json
new file mode 100644
index 0000000..eb77022
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000ffffffff0009.json
@@ -0,0 +1,25 @@
+{
+    "id": "of:0000ffffffff0009",
+    "type": "switch",
+    "propOrder": [
+        "Name",
+        "Vendor",
+        "H/W Version",
+        "S/W Version",
+        "S/W Version",
+        "-",
+        "Latitude",
+        "Longitude",
+        "Ports"
+    ],
+    "props": {
+        "Name": null,
+        "Vendor": "Linc",
+        "H/W Version": "PK",
+        "S/W Version": "?",
+        "-": "",
+        "Latitude": "40.8",
+        "Longitude": "73.1",
+        "Ports": "2"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff07.json b/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff07.json
new file mode 100644
index 0000000..90e5c9d
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff07.json
@@ -0,0 +1,25 @@
+{
+    "id": "of:0000ffffffffff07",
+    "type": "roadm",
+    "propOrder": [
+        "Name",
+        "Vendor",
+        "H/W Version",
+        "S/W Version",
+        "S/W Version",
+        "-",
+        "Latitude",
+        "Longitude",
+        "Ports"
+    ],
+    "props": {
+        "Name": null,
+        "Vendor": "Linc",
+        "H/W Version": "OE",
+        "S/W Version": "?",
+        "-": "",
+        "Latitude": "41.8",
+        "Longitude": "120.1",
+        "Ports": "2"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff09.json b/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff09.json
new file mode 100644
index 0000000..6da31b1
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/json/of_0000ffffffffff09.json
@@ -0,0 +1,25 @@
+{
+    "id": "of:0000ffffffffff09",
+    "type": "roadm",
+    "propOrder": [
+        "Name",
+        "Vendor",
+        "H/W Version",
+        "S/W Version",
+        "S/W Version",
+        "-",
+        "Latitude",
+        "Longitude",
+        "Ports"
+    ],
+    "props": {
+        "Name": null,
+        "Vendor": "Linc",
+        "H/W Version": "OE",
+        "S/W Version": "?",
+        "-": "",
+        "Latitude": "40.8",
+        "Longitude": "73.1",
+        "Ports": "2"
+    }
+}
diff --git a/web/gui/src/main/webapp/OLD/network.js b/web/gui/src/main/webapp/OLD/network.js
new file mode 100644
index 0000000..008ef90
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/network.js
@@ -0,0 +1,1222 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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 network topology viewer - PoC version 1.0
+
+ @author Simon Hunt
+ */
+
+(function (onos) {
+    'use strict';
+
+    // reference to the framework api
+    var api = onos.api;
+
+    // configuration data
+    var config = {
+        useLiveData: false,
+        debugOn: false,
+        debug: {
+            showNodeXY: false,
+            showKeyHandler: true
+        },
+        options: {
+            layering: true,
+            collisionPrevention: true,
+            loadBackground: true
+        },
+        backgroundUrl: 'img/us-map.png',
+        data: {
+            live: {
+                jsonUrl: 'rs/topology/graph',
+                detailPrefix: 'rs/topology/graph/',
+                detailSuffix: ''
+            },
+            fake: {
+                jsonUrl: 'json/network2.json',
+                detailPrefix: 'json/',
+                detailSuffix: '.json'
+            }
+        },
+        iconUrl: {
+            device: 'img/device.png',
+            host: 'img/host.png',
+            pkt: 'img/pkt.png',
+            opt: 'img/opt.png'
+        },
+        mastHeight: 36,
+        force: {
+            note: 'node.class or link.class is used to differentiate',
+            linkDistance: {
+                infra: 200,
+                host: 40
+            },
+            linkStrength: {
+                infra: 1.0,
+                host: 1.0
+            },
+            charge: {
+                device: -800,
+                host: -1000
+            },
+            ticksWithoutCollisions: 50,
+            marginLR: 20,
+            marginTB: 20,
+            translate: function() {
+                return 'translate(' +
+                    config.force.marginLR + ',' +
+                    config.force.marginTB + ')';
+            }
+        },
+        labels: {
+            imgPad: 16,
+            padLR: 8,
+            padTB: 6,
+            marginLR: 3,
+            marginTB: 2,
+            port: {
+                gap: 3,
+                width: 18,
+                height: 14
+            }
+        },
+        icons: {
+            w: 32,
+            h: 32,
+            xoff: -12,
+            yoff: -8
+        },
+        constraints: {
+            ypos: {
+                host: 0.05,
+                switch: 0.3,
+                roadm: 0.7
+            }
+        },
+        hostLinkWidth: 1.0,
+        hostRadius: 7,
+        mouseOutTimerDelayMs: 120
+    };
+
+    // state variables
+    var view = {},
+        network = {},
+        selected = {},
+        highlighted = null,
+        hovered = null,
+        viewMode = 'showAll',
+        portLabelsOn = false;
+
+
+    function debug(what) {
+        return config.debugOn && config.debug[what];
+    }
+
+    function urlData() {
+        return config.data[config.useLiveData ? 'live' : 'fake'];
+    }
+
+    function networkJsonUrl() {
+        return urlData().jsonUrl;
+    }
+
+    function safeId(id) {
+        return id.replace(/[^a-z0-9]/gi, '_');
+    }
+
+    function detailJsonUrl(id) {
+        var u = urlData(),
+            encId = config.useLiveData ? encodeURIComponent(id) : safeId(id);
+        return u.detailPrefix + encId + u.detailSuffix;
+    }
+
+
+    // load the topology view of the network
+    function loadNetworkView() {
+        // Hey, here I am, calling something on the ONOS api:
+        api.printTime();
+
+        resize();
+
+        // go get our network data from the server...
+        var url = networkJsonUrl();
+        d3.json(url , function (err, data) {
+            if (err) {
+                alert('Oops! Error reading JSON...\n\n' +
+                'URL: ' + url + '\n\n' +
+                'Error: ' + err.message);
+                return;
+            }
+//            console.log("here is the JSON data...");
+//            console.log(data);
+
+            network.data = data;
+            drawNetwork();
+        });
+
+        // while we wait for the data, set up the handlers...
+        setUpClickHandler();
+        setUpRadioButtonHandler();
+        setUpKeyHandler();
+        $(window).on('resize', resize);
+    }
+
+    function setUpClickHandler() {
+        // click handler for "selectable" objects
+        $(document).on('click', '.select-object', function () {
+            // when any object of class "select-object" is clicked...
+            var obj = network.lookup[$(this).data('id')];
+            if (obj) {
+                selectObject(obj);
+            }
+            // stop propagation of event (I think) ...
+            return false;
+        });
+    }
+
+    function setUpRadioButtonHandler() {
+        d3.selectAll('#displayModes .radio').on('click', function () {
+            var id = d3.select(this).attr('id');
+            if (id !== viewMode) {
+                radioButton('displayModes', id);
+                viewMode = id;
+                doRadioAction(id);
+            }
+        });
+    }
+
+    function doRadioAction(id) {
+        showAllLayers();
+        if (id === 'showPkt') {
+            showPacketLayer();
+        } else if (id === 'showOpt') {
+            showOpticalLayer();
+        }
+    }
+
+    function showAllLayers() {
+        network.node.classed('inactive', false);
+        network.link.classed('inactive', false);
+        d3.selectAll('svg .port').classed('inactive', false)
+        d3.selectAll('svg .portText').classed('inactive', false)
+    }
+
+    function showPacketLayer() {
+        network.node.each(function(d) {
+            // deactivate nodes that are not hosts or switches
+            if (d.class === 'device' && d.type !== 'switch') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        network.link.each(function(lnk) {
+            // deactivate infrastructure links that have opt's as endpoints
+            if (lnk.source.type === 'roadm' || lnk.target.type === 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        // deactivate non-packet ports
+        d3.selectAll('svg .optPort').classed('inactive', true)
+    }
+
+    function showOpticalLayer() {
+        network.node.each(function(d) {
+            // deactivate nodes that are not optical devices
+            if (d.type !== 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        network.link.each(function(lnk) {
+            // deactivate infrastructure links that have opt's as endpoints
+            if (lnk.source.type !== 'roadm' || lnk.target.type !== 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        // deactivate non-packet ports
+        d3.selectAll('svg .pktPort').classed('inactive', true)
+    }
+
+    function setUpKeyHandler() {
+        d3.select('body')
+            .on('keydown', function () {
+                processKeyEvent();
+                if (debug('showKeyHandler')) {
+                    network.svg.append('text')
+                        .attr('x', 5)
+                        .attr('y', 15)
+                        .style('font-size', '20pt')
+                        .text('keyCode: ' + d3.event.keyCode +
+                        ' applied to : ' + contextLabel())
+                        .transition().duration(2000)
+                        .style('font-size', '2pt')
+                        .style('fill-opacity', 0.01)
+                        .remove();
+                }
+            });
+    }
+
+    function contextLabel() {
+        return hovered === null ? "(nothing)" : hovered.id;
+    }
+
+    function radioButton(group, id) {
+        d3.selectAll("#" + group + " .radio").classed("active", false);
+        d3.select("#" + group + " #" + id).classed("active", true);
+    }
+
+    function processKeyEvent() {
+        var code = d3.event.keyCode;
+        switch (code) {
+            case 66:    // B
+                toggleBackground();
+                break;
+            case 71:    // G
+                cycleLayout();
+                break;
+            case 76:    // L
+                cycleLabels();
+                break;
+            case 80:    // P
+                togglePorts();
+                break;
+            case 85:    // U
+                unpin();
+                break;
+        }
+
+    }
+
+    function toggleBackground() {
+        var bg = d3.select('#bg'),
+            vis = bg.style('visibility'),
+            newvis = (vis === 'hidden') ? 'visible' : 'hidden';
+        bg.style('visibility', newvis);
+    }
+
+    function cycleLayout() {
+        config.options.layering = !config.options.layering;
+        network.force.resume();
+    }
+
+    function cycleLabels() {
+        console.log('Cycle Labels - context = ' + contextLabel());
+    }
+
+    function togglePorts() {
+        portLabelsOn = !portLabelsOn;
+        var portVis = portLabelsOn ? 'visible' : 'hidden';
+        d3.selectAll('.port').style('visibility', portVis);
+        d3.selectAll('.portText').style('visibility', portVis);
+    }
+
+    function unpin() {
+        if (hovered) {
+            hovered.fixed = false;
+            findNodeFromData(hovered).classed('fixed', false);
+            network.force.resume();
+        }
+        console.log('Unpin - context = ' + contextLabel());
+    }
+
+
+    // ========================================================
+
+    function drawNetwork() {
+        $('#view').empty();
+
+        prepareNodesAndLinks();
+        createLayout();
+        console.log("\n\nHere is the augmented network object...");
+        console.log(network);
+    }
+
+    function prepareNodesAndLinks() {
+        network.lookup = {};
+        network.nodes = [];
+        network.links = [];
+
+        var nw = network.forceWidth,
+            nh = network.forceHeight;
+
+        function yPosConstraintForNode(n) {
+            return config.constraints.ypos[n.type || 'host'];
+        }
+
+        // Note that both 'devices' and 'hosts' get mapped into the nodes array
+
+        // first, the devices...
+        network.data.devices.forEach(function(n) {
+            var ypc = yPosConstraintForNode(n),
+                ix = Math.random() * 0.6 * nw + 0.2 * nw,
+                iy = ypc * nh,
+                node = {
+                    id: n.id,
+                    labels: n.labels,
+                    class: 'device',
+                    icon: 'device',
+                    type: n.type,
+                    x: ix,
+                    y: iy,
+                    constraint: {
+                        weight: 0.7,
+                        y: iy
+                    }
+                };
+            network.lookup[n.id] = node;
+            network.nodes.push(node);
+        });
+
+        // then, the hosts...
+        network.data.hosts.forEach(function(n) {
+            var ypc = yPosConstraintForNode(n),
+                ix = Math.random() * 0.6 * nw + 0.2 * nw,
+                iy = ypc * nh,
+                node = {
+                    id: n.id,
+                    labels: n.labels,
+                    class: 'host',
+                    icon: 'host',
+                    type: n.type,
+                    x: ix,
+                    y: iy,
+                    constraint: {
+                        weight: 0.7,
+                        y: iy
+                    }
+                };
+            network.lookup[n.id] = node;
+            network.nodes.push(node);
+        });
+
+
+        // now, process the explicit links...
+        network.data.links.forEach(function(lnk) {
+            var src = network.lookup[lnk.src],
+                dst = network.lookup[lnk.dst],
+                id = src.id + "-" + dst.id;
+
+            var link = {
+                class: 'infra',
+                id: id,
+                type: lnk.type,
+                width: lnk.linkWidth,
+                source: src,
+                srcPort: lnk.srcPort,
+                target: dst,
+                tgtPort: lnk.dstPort,
+                strength: config.force.linkStrength.infra
+            };
+            network.links.push(link);
+        });
+
+        // finally, infer host links...
+        network.data.hosts.forEach(function(n) {
+            var src = network.lookup[n.id],
+                dst = network.lookup[n.cp.device],
+                id = src.id + "-" + dst.id;
+
+            var link = {
+                class: 'host',
+                id: id,
+                type: 'hostLink',
+                width: config.hostLinkWidth,
+                source: src,
+                target: dst,
+                strength: config.force.linkStrength.host
+            };
+            network.links.push(link);
+        });
+    }
+
+    function createLayout() {
+
+        var cfg = config.force;
+
+        network.force = d3.layout.force()
+            .size([network.forceWidth, network.forceHeight])
+            .nodes(network.nodes)
+            .links(network.links)
+            .linkStrength(function(d) { return cfg.linkStrength[d.class]; })
+            .linkDistance(function(d) { return cfg.linkDistance[d.class]; })
+            .charge(function(d) { return cfg.charge[d.class]; })
+            .on('tick', tick);
+
+        network.svg = d3.select('#view').append('svg')
+            .attr('width', view.width)
+            .attr('height', view.height)
+            .append('g')
+            .attr('transform', config.force.translate());
+//            .attr('id', 'zoomable')
+//            .call(d3.behavior.zoom().on("zoom", zoomRedraw));
+
+        network.svg.append('svg:image')
+            .attr({
+                id: 'bg',
+                width: view.width,
+                height: view.height,
+                'xlink:href': config.backgroundUrl
+            })
+            .style('visibility',
+            config.options.loadBackground ? 'visible' : 'hidden');
+
+//        function zoomRedraw() {
+//            d3.select("#zoomable").attr("transform",
+//                    "translate(" + d3.event.translate + ")"
+//                    + " scale(" + d3.event.scale + ")");
+//        }
+
+        // TODO: move glow/blur stuff to util script
+        var glow = network.svg.append('filter')
+            .attr('x', '-50%')
+            .attr('y', '-50%')
+            .attr('width', '200%')
+            .attr('height', '200%')
+            .attr('id', 'blue-glow');
+
+        glow.append('feColorMatrix')
+            .attr('type', 'matrix')
+            .attr('values', '0 0 0 0  0 ' +
+            '0 0 0 0  0 ' +
+            '0 0 0 0  .7 ' +
+            '0 0 0 1  0 ');
+
+        glow.append('feGaussianBlur')
+            .attr('stdDeviation', 3)
+            .attr('result', 'coloredBlur');
+
+        glow.append('feMerge').selectAll('feMergeNode')
+            .data(['coloredBlur', 'SourceGraphic'])
+            .enter().append('feMergeNode')
+            .attr('in', String);
+
+        // TODO: legend (and auto adjust on scroll)
+//        $('#view').on('scroll', function() {
+//
+//        });
+
+
+        // TODO: move drag behavior into separate method.
+        // == define node drag behavior...
+        network.draggedThreshold = d3.scale.linear()
+            .domain([0, 0.1])
+            .range([5, 20])
+            .clamp(true);
+
+        function dragged(d) {
+            var threshold = network.draggedThreshold(network.force.alpha()),
+                dx = d.oldX - d.px,
+                dy = d.oldY - d.py;
+            if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
+                d.dragged = true;
+            }
+            return d.dragged;
+        }
+
+        network.drag = d3.behavior.drag()
+            .origin(function(d) { return d; })
+            .on('dragstart', function(d) {
+                d.oldX = d.x;
+                d.oldY = d.y;
+                d.dragged = false;
+                d.fixed |= 2;
+            })
+            .on('drag', function(d) {
+                d.px = d3.event.x;
+                d.py = d3.event.y;
+                if (dragged(d)) {
+                    if (!network.force.alpha()) {
+                        network.force.alpha(.025);
+                    }
+                }
+            })
+            .on('dragend', function(d) {
+                if (!dragged(d)) {
+                    selectObject(d, this);
+                }
+                d.fixed &= ~6;
+
+                // once we've finished moving, pin the node in position,
+                // if it is a device (not a host)
+                if (d.class === 'device') {
+                    d.fixed = true;
+                    d3.select(this).classed('fixed', true)
+                }
+            });
+
+        $('#view').on('click', function(e) {
+            if (!$(e.target).closest('.node').length) {
+                deselectObject();
+            }
+        });
+
+        // ...............................................................
+
+        // add links to the display
+        network.link = network.svg.append('g').attr('id', 'links')
+            .selectAll('.link')
+            .data(network.force.links(), function(d) {return d.id})
+            .enter().append('line')
+            .attr('class', function(d) {return 'link ' + d.class});
+
+        network.linkSrcPort = network.svg.append('g')
+            .attr({
+                id: 'srcPorts',
+                class: 'portLayer'
+            });
+        network.linkTgtPort = network.svg.append('g')
+            .attr({
+                id: 'tgtPorts',
+                class: 'portLayer'
+            });
+
+        var portVis = portLabelsOn ? 'visible' : 'hidden',
+            pw = config.labels.port.width,
+            ph = config.labels.port.height;
+
+        network.link.filter('.infra').each(function(d) {
+            var srcType = d.source.type === 'roadm' ? 'optPort' : 'pktPort',
+                tgtType = d.target.type === 'roadm' ? 'optPort' : 'pktPort';
+
+            if (d.source.type)
+
+                network.linkSrcPort.append('rect').attr({
+                    id: 'srcPort-' + safeId(d.id),
+                    class: 'port ' + srcType,
+                    width: pw,
+                    height: ph,
+                    rx: 4,
+                    ry: 4
+                }).style('visibility', portVis);
+
+            network.linkTgtPort.append('rect').attr({
+                id: 'tgtPort-' + safeId(d.id),
+                class: 'port ' + tgtType,
+                width: pw,
+                height: ph,
+                rx: 4,
+                ry: 4
+            }).style('visibility', portVis);
+
+            network.linkSrcPort.append('text').attr({
+                id: 'srcText-' + safeId(d.id),
+                class: 'portText ' + srcType
+            }).text(d.srcPort)
+                .style('visibility', portVis);
+
+            network.linkTgtPort.append('text').attr({
+                id: 'tgtText-' + safeId(d.id),
+                class: 'portText ' + tgtType
+            }).text(d.tgtPort)
+                .style('visibility', portVis);
+        });
+
+        // ...............................................................
+
+        // add nodes to the display
+        network.node = network.svg.selectAll('.node')
+            .data(network.force.nodes(), function(d) {return d.id})
+            .enter().append('g')
+            .attr('class', function(d) {
+                var cls = 'node ' + d.class;
+                if (d.type) {
+                    cls += ' ' + d.type;
+                }
+                return cls;
+            })
+            .attr('transform', function(d) {
+                return translate(d.x, d.y);
+            })
+            .call(network.drag)
+            .on('mouseover', function(d) {
+                // TODO: show tooltip
+                if (network.mouseoutTimeout) {
+                    clearTimeout(network.mouseoutTimeout);
+                    network.mouseoutTimeout = null;
+                }
+                hoverObject(d);
+            })
+            .on('mouseout', function(d) {
+                // TODO: hide tooltip
+                if (network.mouseoutTimeout) {
+                    clearTimeout(network.mouseoutTimeout);
+                    network.mouseoutTimeout = null;
+                }
+                network.mouseoutTimeout = setTimeout(function() {
+                    hoverObject(null);
+                }, config.mouseOutTimerDelayMs);
+            });
+
+
+        // deal with device nodes first
+        network.nodeRect = network.node.filter('.device')
+            .append('rect')
+            .attr({
+                rx: 5,
+                ry: 5,
+                width: 100,
+                height: 12
+            });
+        // note that width/height are adjusted to fit the label text
+        // then padded, and space made for the icon.
+
+        network.node.filter('.device').each(function(d) {
+            var node = d3.select(this),
+                icon = iconUrl(d);
+
+            node.append('text')
+                // TODO: add label cycle behavior
+                .text(d.id)
+                .attr('dy', '1.1em');
+
+            if (icon) {
+                var cfg = config.icons;
+                node.append('svg:image')
+                    .attr({
+                        width: cfg.w,
+                        height: cfg.h,
+                        'xlink:href': icon
+                    });
+                // note, icon relative positioning (x,y) is done after we have
+                // adjusted the bounds of the rectangle...
+            }
+
+            // debug function to show the modelled x,y coordinates of nodes...
+            if (debug('showNodeXY')) {
+                node.select('rect').attr('fill-opacity', 0.5);
+                node.append('circle')
+                    .attr({
+                        class: 'debug',
+                        cx: 0,
+                        cy: 0,
+                        r: '3px'
+                    });
+            }
+        });
+
+        // now process host nodes
+        network.nodeCircle = network.node.filter('.host')
+            .append('circle')
+            .attr({
+                r: config.hostRadius
+            });
+
+        network.node.filter('.host').each(function(d) {
+            var node = d3.select(this),
+                icon = iconUrl(d);
+
+            // debug function to show the modelled x,y coordinates of nodes...
+            if (debug('showNodeXY')) {
+                node.select('circle').attr('fill-opacity', 0.5);
+                node.append('circle')
+                    .attr({
+                        class: 'debug',
+                        cx: 0,
+                        cy: 0,
+                        r: '3px'
+                    });
+            }
+        });
+
+        // this function is scheduled to happen soon after the given thread ends
+        setTimeout(function() {
+            var lab = config.labels,
+                portGap = lab.port.gap,
+                midW = portGap + lab.port.width/ 2,
+                midH = portGap + lab.port.height / 2;
+
+            // post process the device nodes, to pad their size to fit the
+            // label text and attach the icon to the right location.
+            network.node.filter('.device').each(function(d) {
+                // for every node, recompute size, padding, etc. so text fits
+                var node = d3.select(this),
+                    text = node.select('text'),
+                    box = adjustRectToFitText(node);
+
+                // now make the computed adjustment
+                node.select('rect')
+                    .attr(box);
+
+                node.select('image')
+                    .attr('x', box.x + config.icons.xoff)
+                    .attr('y', box.y + config.icons.yoff);
+
+                var bounds = boundsFromBox(box),
+                    portBounds = {
+                        x1: bounds.x1 - midW,
+                        x2: bounds.x2 + midW,
+                        y1: bounds.y1 - midH,
+                        y2: bounds.y2 + midH
+                    };
+
+                // todo: clean up extent and edge work..
+                d.extent = {
+                    left: bounds.x1 - lab.marginLR,
+                    right: bounds.x2 + lab.marginLR,
+                    top: bounds.y1 - lab.marginTB,
+                    bottom: bounds.y2 + lab.marginTB
+                };
+
+                d.edge = {
+                    left   : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x1, bounds.y2),
+                    right  : new geo.LineSegment(bounds.x2, bounds.y1, bounds.x2, bounds.y2),
+                    top    : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x2, bounds.y1),
+                    bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2)
+                };
+
+                d.portEdge = {
+                    left   : new geo.LineSegment(
+                        portBounds.x1, portBounds.y1, portBounds.x1, portBounds.y2
+                    ),
+                    right  : new geo.LineSegment(
+                        portBounds.x2, portBounds.y1, portBounds.x2, portBounds.y2
+                    ),
+                    top    : new geo.LineSegment(
+                        portBounds.x1, portBounds.y1, portBounds.x2, portBounds.y1
+                    ),
+                    bottom : new geo.LineSegment(
+                        portBounds.x1, portBounds.y2, portBounds.x2, portBounds.y2
+                    )
+                };
+
+            });
+
+            network.numTicks = 0;
+            network.preventCollisions = false;
+            network.force.start();
+            for (var i = 0; i < config.force.ticksWithoutCollisions; i++) {
+                network.force.tick();
+            }
+            network.preventCollisions = true;
+            $('#view').css('visibility', 'visible');
+        });
+
+
+        // returns the newly computed bounding box of the rectangle
+        function adjustRectToFitText(n) {
+            var text = n.select('text'),
+                box = text.node().getBBox(),
+                lab = config.labels;
+
+            // not sure why n.data() returns an array of 1 element...
+            var data = n.data()[0];
+
+            text.attr('text-anchor', 'middle')
+                .attr('y', '-0.8em')
+                .attr('x', lab.imgPad/2)
+            ;
+
+            // translate the bbox so that it is centered on [x,y]
+            box.x = -box.width / 2;
+            box.y = -box.height / 2;
+
+            // add padding
+            box.x -= (lab.padLR + lab.imgPad/2);
+            box.width += lab.padLR * 2 + lab.imgPad;
+            box.y -= lab.padTB;
+            box.height += lab.padTB * 2;
+
+            return box;
+        }
+
+        function boundsFromBox(box) {
+            return {
+                x1: box.x,
+                y1: box.y,
+                x2: box.x + box.width,
+                y2: box.y + box.height
+            };
+        }
+
+    }
+
+    function iconUrl(d) {
+        return 'img/' + d.type + '.png';
+//        return config.iconUrl[d.icon];
+    }
+
+    function translate(x, y) {
+        return 'translate(' + x + ',' + y + ')';
+    }
+
+    // prevents collisions amongst device nodes
+    function preventCollisions() {
+        var quadtree = d3.geom.quadtree(network.nodes),
+            hrad = config.hostRadius;
+
+        network.nodes.forEach(function(n) {
+            var nx1, nx2, ny1, ny2;
+
+            if (n.class === 'device') {
+                nx1 = n.x + n.extent.left;
+                nx2 = n.x + n.extent.right;
+                ny1 = n.y + n.extent.top;
+                ny2 = n.y + n.extent.bottom;
+
+            } else {
+                nx1 = n.x - hrad;
+                nx2 = n.x + hrad;
+                ny1 = n.y - hrad;
+                ny2 = n.y + hrad;
+            }
+
+            quadtree.visit(function(quad, x1, y1, x2, y2) {
+                if (quad.point && quad.point !== n) {
+                    // check if the rectangles/circles intersect
+                    var p = quad.point,
+                        px1, px2, py1, py2, ix;
+
+                    if (p.class === 'device') {
+                        px1 = p.x + p.extent.left;
+                        px2 = p.x + p.extent.right;
+                        py1 = p.y + p.extent.top;
+                        py2 = p.y + p.extent.bottom;
+
+                    } else {
+                        px1 = p.x - hrad;
+                        px2 = p.x + hrad;
+                        py1 = p.y - hrad;
+                        py2 = p.y + hrad;
+                    }
+
+                    ix = (px1 <= nx2 && nx1 <= px2 && py1 <= ny2 && ny1 <= py2);
+
+                    if (ix) {
+                        var xa1 = nx2 - px1, // shift n left , p right
+                            xa2 = px2 - nx1, // shift n right, p left
+                            ya1 = ny2 - py1, // shift n up   , p down
+                            ya2 = py2 - ny1, // shift n down , p up
+                            adj = Math.min(xa1, xa2, ya1, ya2);
+
+                        if (adj == xa1) {
+                            n.x -= adj / 2;
+                            p.x += adj / 2;
+                        } else if (adj == xa2) {
+                            n.x += adj / 2;
+                            p.x -= adj / 2;
+                        } else if (adj == ya1) {
+                            n.y -= adj / 2;
+                            p.y += adj / 2;
+                        } else if (adj == ya2) {
+                            n.y += adj / 2;
+                            p.y -= adj / 2;
+                        }
+                    }
+                    return ix;
+                }
+            });
+
+        });
+    }
+
+    function tick(e) {
+        network.numTicks++;
+
+        if (config.options.layering) {
+            // adjust the y-coord of each node, based on y-pos constraints
+            network.nodes.forEach(function (n) {
+                var z = e.alpha * n.constraint.weight;
+                if (!isNaN(n.constraint.y)) {
+                    n.y = (n.constraint.y * z + n.y * (1 - z));
+                }
+            });
+        }
+
+        if (config.options.collisionPrevention && network.preventCollisions) {
+            preventCollisions();
+        }
+
+        var portHalfW = config.labels.port.width / 2,
+            portHalfH = config.labels.port.height / 2;
+
+        // clip visualization of links at bounds of nodes...
+        network.link.each(function(d) {
+            var xs = d.source.x,
+                ys = d.source.y,
+                xt = d.target.x,
+                yt = d.target.y,
+                line = new geo.LineSegment(xs, ys, xt, yt),
+                e, ix,
+                exs, eys, ext, eyt,
+                pxs, pys, pxt, pyt;
+
+            if (d.class === 'host') {
+                // no adjustment for source end of link, since hosts are dots
+                exs = xs;
+                eys = ys;
+
+            } else {
+                for (e in d.source.edge) {
+                    ix = line.intersect(d.source.edge[e].offset(xs, ys));
+                    if (ix.in1 && ix.in2) {
+                        exs = ix.x;
+                        eys = ix.y;
+
+                        // also pick off the port label intersection
+                        ix = line.intersect(d.source.portEdge[e].offset(xs, ys));
+                        pxs = ix.x;
+                        pys = ix.y;
+                        break;
+                    }
+                }
+            }
+
+            for (e in d.target.edge) {
+                ix = line.intersect(d.target.edge[e].offset(xt, yt));
+                if (ix.in1 && ix.in2) {
+                    ext = ix.x;
+                    eyt = ix.y;
+
+                    // also pick off the port label intersection
+                    ix = line.intersect(d.target.portEdge[e].offset(xt, yt));
+                    pxt = ix.x;
+                    pyt = ix.y;
+                    break;
+                }
+            }
+
+            // adjust the endpoints of the link's line to match rectangles
+            var sid = safeId(d.id);
+            d3.select(this)
+                .attr('x1', exs)
+                .attr('y1', eys)
+                .attr('x2', ext)
+                .attr('y2', eyt);
+
+            d3.select('#srcPort-' + sid)
+                .attr('x', pxs - portHalfW)
+                .attr('y', pys - portHalfH);
+
+            d3.select('#tgtPort-' + sid)
+                .attr('x', pxt - portHalfW)
+                .attr('y', pyt - portHalfH);
+
+            // TODO: fit label rect to size of port number.
+            d3.select('#srcText-' + sid)
+                .attr('x', pxs - 5)
+                .attr('y', pys + 3);
+
+            d3.select('#tgtText-' + sid)
+                .attr('x', pxt - 5)
+                .attr('y', pyt + 3);
+
+        });
+
+        // position each node by translating the node (group) by x,y
+        network.node
+            .attr('transform', function(d) {
+                return translate(d.x, d.y);
+            });
+
+    }
+
+    //    $('#docs-close').on('click', function() {
+    //        deselectObject();
+    //        return false;
+    //    });
+
+    //    $(document).on('click', '.select-object', function() {
+    //        var obj = graph.data[$(this).data('name')];
+    //        if (obj) {
+    //            selectObject(obj);
+    //        }
+    //        return false;
+    //    });
+
+    function findNodeFromData(d) {
+        var el = null;
+        network.node.filter('.' + d.class).each(function(n) {
+            if (n.id === d.id) {
+                el = d3.select(this);
+            }
+        });
+        return el;
+    }
+
+    function selectObject(obj, el) {
+        var node;
+        if (el) {
+            node = d3.select(el);
+        } else {
+            network.node.each(function(d) {
+                if (d == obj) {
+                    node = d3.select(el = this);
+                }
+            });
+        }
+        if (!node) return;
+
+        if (node.classed('selected')) {
+            deselectObject();
+            flyinPane(null);
+            return;
+        }
+        deselectObject(false);
+
+        selected = {
+            obj : obj,
+            el  : el
+        };
+
+        node.classed('selected', true);
+        flyinPane(obj);
+    }
+
+    function deselectObject(doResize) {
+        // Review: logic of 'resize(...)' function.
+        if (doResize || typeof doResize == 'undefined') {
+            resize(false);
+        }
+
+        // deselect all nodes in the network...
+        network.node.classed('selected', false);
+        selected = {};
+        flyinPane(null);
+    }
+
+    function flyinPane(obj) {
+        var pane = d3.select('#flyout'),
+            url;
+
+        if (obj) {
+            // go get details of the selected object from the server...
+            url = detailJsonUrl(obj.id);
+            d3.json(url, function (err, data) {
+                if (err) {
+                    alert('Oops! Error reading JSON...\n\n' +
+                    'URL: ' + url + '\n\n' +
+                    'Error: ' + err.message);
+                    return;
+                }
+//                console.log("JSON data... " + url);
+//                console.log(data);
+
+                displayDetails(data, pane);
+            });
+
+        } else {
+            // hide pane
+            pane.transition().duration(750)
+                .style('right', '-320px')
+                .style('opacity', 0.0);
+        }
+    }
+
+    function displayDetails(data, pane) {
+        $('#flyout').empty();
+
+        var title = pane.append("h2"),
+            table = pane.append("table"),
+            tbody = table.append("tbody");
+
+        $('<img src="img/' + data.type + '.png">').appendTo(title);
+        $('<span>').attr('class', 'icon').text(data.id).appendTo(title);
+
+
+        // TODO: consider using d3 data bind to TR/TD
+
+        data.propOrder.forEach(function(p) {
+            if (p === '-') {
+                addSep(tbody);
+            } else {
+                addProp(tbody, p, data.props[p]);
+            }
+        });
+
+        function addSep(tbody) {
+            var tr = tbody.append('tr');
+            $('<hr>').appendTo(tr.append('td').attr('colspan', 2));
+        }
+
+        function addProp(tbody, label, value) {
+            var tr = tbody.append('tr');
+
+            tr.append('td')
+                .attr('class', 'label')
+                .text(label + ' :');
+
+            tr.append('td')
+                .attr('class', 'value')
+                .text(value);
+        }
+
+        // show pane
+        pane.transition().duration(750)
+            .style('right', '20px')
+            .style('opacity', 1.0);
+    }
+
+    function highlightObject(obj) {
+        if (obj) {
+            if (obj != highlighted) {
+                // TODO set or clear "inactive" class on nodes, based on criteria
+                network.node.classed('inactive', function(d) {
+                    //                return (obj !== d &&
+                    //                    d.relation(obj.id));
+                    return (obj !== d);
+                });
+                // TODO: same with links
+                network.link.classed('inactive', function(d) {
+                    return (obj !== d.source && obj !== d.target);
+                });
+            }
+            highlighted = obj;
+        } else {
+            if (highlighted) {
+                // clear the inactive flag (no longer suppressed visually)
+                network.node.classed('inactive', false);
+                network.link.classed('inactive', false);
+            }
+            highlighted = null;
+
+        }
+    }
+
+    function hoverObject(obj) {
+        if (obj) {
+            hovered = obj;
+        } else {
+            if (hovered) {
+                hovered = null;
+            }
+        }
+    }
+
+
+    function resize() {
+        view.height = window.innerHeight - config.mastHeight;
+        view.width = window.innerWidth;
+        $('#view')
+            .css('height', view.height + 'px')
+            .css('width', view.width + 'px');
+
+        network.forceWidth = view.width - config.force.marginLR;
+        network.forceHeight = view.height - config.force.marginTB;
+    }
+
+    // ======================================================================
+    // register with the UI framework
+
+    api.addView('network', {
+        load: loadNetworkView
+    });
+
+
+}(ONOS));
+
diff --git a/web/gui/src/main/webapp/OLD/onos.css b/web/gui/src/main/webapp/OLD/onos.css
new file mode 100644
index 0000000..061cb5b
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/onos.css
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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 CSS file
+
+ @author Simon Hunt
+ */
+
+body, html {
+    height: 100%;
+}
+
+/*
+ * Classes
+ */
+
+img#logo {
+    height: 38px;
+    padding-left: 8px;
+    padding-right: 8px;
+}
+
+span.title {
+    color: #369;
+    font-size: 14pt;
+    font-style: italic;
+    vertical-align: 12px;
+}
+
+span.radio {
+    color: darkslateblue;
+    font-size: 10pt;
+}
+
+span.right {
+    padding-top: 8px;
+    padding-right: 16px;
+    float: right;
+}
+
+/*
+ * Radio Buttons
+ */
+
+span.radio {
+    margin: 4px 0;
+    border: 1px dotted #222;
+    padding: 1px 6px;
+    color: #eee;
+    cursor: pointer;
+}
+
+span.radio.active {
+    background-color: #bbb;
+    border: 1px solid #eee;
+    padding: 1px 6px;
+    color: #666;
+    font-weight: bold;
+}
+
+/*
+ * === DEBUGGING ======
+ */
+svg {
+    /*border: 1px dashed red;*/
+}
+
+svg #bg {
+    opacity: 0.5;
+}
+
+
+/*
+ * Network Graph elements ======================================
+ */
+
+svg .link {
+    fill: none;
+    stroke: #666;
+    stroke-width: 2.0px;
+    opacity: .7;
+
+    transition: opacity 250ms;
+    -webkit-transition: opacity 250ms;
+    -moz-transition: opacity 250ms;
+}
+
+svg .link.host {
+    stroke: #666;
+    stroke-width: 1px;
+}
+
+svg g.portLayer rect.port {
+    fill: #ccc;
+}
+
+svg g.portLayer text {
+    font: 8pt sans-serif;
+    pointer-events: none;
+}
+
+svg .node.device rect {
+    stroke-width: 1.5px;
+
+    transition: opacity 250ms;
+    -webkit-transition: opacity 250ms;
+    -moz-transition: opacity 250ms;
+}
+
+svg .node.device.fixed rect {
+    stroke-width: 1.5;
+    stroke: #ccc;
+}
+
+svg .node.device.roadm rect {
+    fill: #03c;
+}
+
+svg .node.device.switch rect {
+    fill: #06f;
+}
+
+svg .node.host circle {
+    fill: #c96;
+    stroke: #000;
+}
+
+svg .node text {
+    fill: white;
+    font: 10pt sans-serif;
+    pointer-events: none;
+}
+
+/* for debugging */
+svg .node circle.debug {
+    fill: white;
+    stroke: red;
+}
+svg .node rect.debug {
+    fill: yellow;
+    stroke: red;
+    opacity: 0.35;
+}
+
+
+svg .node.selected rect,
+svg .node.selected circle {
+    filter: url(#blue-glow);
+}
+
+svg .link.inactive,
+svg .port.inactive,
+svg .portText.inactive,
+svg .node.inactive rect,
+svg .node.inactive circle,
+svg .node.inactive text,
+svg .node.inactive image {
+    opacity: .1;
+}
+
+svg .node.inactive.selected rect,
+svg .node.inactive.selected text,
+svg .node.inactive.selected image {
+    opacity: .6;
+}
+
+/*
+ * === currently unused ===============================================
+ */
+
+svg marker#end {
+    fill: #666;
+    stroke: #666;
+    stroke-width: 1.5px;
+}
+
+svg .legend {
+    position: fixed;
+}
+
+svg .legend .category rect {
+    stroke-width: 1px;
+}
+
+svg .legend .category text {
+    fill: #000;
+    font: 10px sans-serif;
+    pointer-events: none;
+}
+
+/*
+ * =============================================================
+ */
+
+/*
+ * Specific structural elements
+ */
+
+/* This is to ensure that the body does not expand to account for the
+   flyout details pane, that is positioned "off screen".
+ */
+body {
+    overflow: hidden;
+}
+
+#mast {
+    height: 36px;
+    padding: 4px;
+    background-color: #bbb;
+    vertical-align: baseline;
+    box-shadow: 0px 2px 8px #777;
+}
+
+#frame {
+    width: 100%;
+    height: 100%;
+    background-color: #fff;
+}
+
+#flyout {
+    position: absolute;
+    z-index: 100;
+    display: block;
+    top: 10%;
+    width: 280px;
+    right: -300px;
+    opacity: 0;
+    background-color: rgba(255,255,255,0.8);
+
+    padding: 10px;
+    color: black;
+    font-size: 10pt;
+    box-shadow: 2px 2px 16px #777;
+}
+
+#flyout h2 {
+    margin: 8px 4px;
+    color: black;
+    vertical-align: middle;
+}
+
+#flyout h2 img {
+    height: 32px;
+    padding-right: 8px;
+    vertical-align: middle;
+}
+
+#flyout p, table {
+    margin: 4px 4px;
+}
+
+#flyout td.label {
+    font-style: italic;
+    color: #777;
+    padding-right: 12px;
+}
+
+#flyout td.value {
+
+}
+
+#flyout hr {
+    height: 1px;
+    color: #ccc;
+    background-color: #ccc;
+    border: 0;
+}
+
diff --git a/web/gui/src/main/webapp/OLD/onos.js b/web/gui/src/main/webapp/OLD/onos.js
new file mode 100644
index 0000000..7153d76d0
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/onos.js
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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 UI Framework.
+
+ @author Simon Hunt
+ */
+
+(function ($) {
+    'use strict';
+    var tsI = new Date().getTime(),         // initialize time stamp
+        tsB;                                // build time stamp
+
+    // attach our main function to the jQuery object
+    $.onos = function (options) {
+        // private namespaces
+        var publicApi;             // public api
+
+        // internal state
+        var views = {},
+            currentView = null,
+            built = false;
+
+        // DOM elements etc.
+        var $mast;
+
+
+        // various functions..................
+
+        // throw an error
+        function throwError(msg) {
+            // todo: maybe add tracing later
+            throw new Error(msg);
+        }
+
+        // define all the public api functions...
+        publicApi = {
+            printTime: function () {
+                console.log("the time is " + new Date());
+            },
+
+            addView: function (vid, cb) {
+                views[vid] = {
+                    vid: vid,
+                    cb: cb
+                };
+                // TODO: proper registration of views
+                // for now, make the one (and only) view current..
+                currentView = views[vid];
+            }
+        };
+
+        // function to be called from index.html to build the ONOS UI
+        function buildOnosUi() {
+            tsB = new Date().getTime();
+            tsI = tsB - tsI; // initialization duration
+
+            console.log('ONOS UI initialized in ' + tsI + 'ms');
+
+            if (built) {
+                throwError("ONOS UI already built!");
+            }
+            built = true;
+
+            // TODO: invoke hash navigation
+            // --- report build errors ---
+
+            // for now, invoke the one and only load function:
+
+            currentView.cb.load();
+        }
+
+
+        // export the api and build-UI function
+        return {
+            api: publicApi,
+            buildUi: buildOnosUi
+        };
+    };
+
+}(jQuery));
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/OLD/topo2-OLD.js b/web/gui/src/main/webapp/OLD/topo2-OLD.js
new file mode 100644
index 0000000..04ce7ab
--- /dev/null
+++ b/web/gui/src/main/webapp/OLD/topo2-OLD.js
@@ -0,0 +1,1219 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * 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 network topology viewer - PoC version 1.0
+
+ @author Simon Hunt
+ */
+
+(function (onos) {
+    'use strict';
+
+    // configuration data
+    var config = {
+        useLiveData: true,
+        debugOn: false,
+        debug: {
+            showNodeXY: false,
+            showKeyHandler: true
+        },
+        options: {
+            layering: true,
+            collisionPrevention: true,
+            loadBackground: true
+        },
+        backgroundUrl: 'img/us-map.png',
+        data: {
+            live: {
+                jsonUrl: 'rs/topology/graph',
+                detailPrefix: 'rs/topology/graph/',
+                detailSuffix: ''
+            },
+            fake: {
+                jsonUrl: 'json/network2.json',
+                detailPrefix: 'json/',
+                detailSuffix: '.json'
+            }
+        },
+        iconUrl: {
+            device: 'img/device.png',
+            host: 'img/host.png',
+            pkt: 'img/pkt.png',
+            opt: 'img/opt.png'
+        },
+        mastHeight: 36,
+        force: {
+            note: 'node.class or link.class is used to differentiate',
+            linkDistance: {
+                infra: 200,
+                host: 40
+            },
+            linkStrength: {
+                infra: 1.0,
+                host: 1.0
+            },
+            charge: {
+                device: -800,
+                host: -1000
+            },
+            ticksWithoutCollisions: 50,
+            marginLR: 20,
+            marginTB: 20,
+            translate: function() {
+                return 'translate(' +
+                    config.force.marginLR + ',' +
+                    config.force.marginTB + ')';
+            }
+        },
+        labels: {
+            imgPad: 16,
+            padLR: 8,
+            padTB: 6,
+            marginLR: 3,
+            marginTB: 2,
+            port: {
+                gap: 3,
+                width: 18,
+                height: 14
+            }
+        },
+        icons: {
+            w: 32,
+            h: 32,
+            xoff: -12,
+            yoff: -8
+        },
+        constraints: {
+            ypos: {
+                host: 0.05,
+                switch: 0.3,
+                roadm: 0.7
+            }
+        },
+        hostLinkWidth: 1.0,
+        hostRadius: 7,
+        mouseOutTimerDelayMs: 120
+    };
+
+    // state variables
+    var netView = {},
+        network = {},
+        selected = {},
+        highlighted = null,
+        hovered = null,
+        viewMode = 'showAll',
+        portLabelsOn = false;
+
+
+    function debug(what) {
+        return config.debugOn && config.debug[what];
+    }
+
+    function urlData() {
+        return config.data[config.useLiveData ? 'live' : 'fake'];
+    }
+
+    function networkJsonUrl() {
+        return urlData().jsonUrl;
+    }
+
+    function safeId(id) {
+        return id.replace(/[^a-z0-9]/gi, '_');
+    }
+
+    function detailJsonUrl(id) {
+        var u = urlData(),
+            encId = config.useLiveData ? encodeURIComponent(id) : safeId(id);
+        return u.detailPrefix + encId + u.detailSuffix;
+    }
+
+
+    // load the topology view of the network
+    function loadNetworkView() {
+        // Hey, here I am, calling something on the ONOS api:
+        api.printTime();
+
+        resize();
+
+        // go get our network data from the server...
+        var url = networkJsonUrl();
+        d3.json(url , function (err, data) {
+            if (err) {
+                alert('Oops! Error reading JSON...\n\n' +
+                    'URL: ' + url + '\n\n' +
+                    'Error: ' + err.message);
+                return;
+            }
+//            console.log("here is the JSON data...");
+//            console.log(data);
+
+            network.data = data;
+            drawNetwork();
+        });
+
+        // while we wait for the data, set up the handlers...
+        setUpClickHandler();
+        setUpRadioButtonHandler();
+        setUpKeyHandler();
+        $(window).on('resize', resize);
+    }
+
+    function setUpClickHandler() {
+        // click handler for "selectable" objects
+        $(document).on('click', '.select-object', function () {
+            // when any object of class "select-object" is clicked...
+            var obj = network.lookup[$(this).data('id')];
+            if (obj) {
+                selectObject(obj);
+            }
+            // stop propagation of event (I think) ...
+            return false;
+        });
+    }
+
+    function setUpRadioButtonHandler() {
+        d3.selectAll('#displayModes .radio').on('click', function () {
+            var id = d3.select(this).attr('id');
+            if (id !== viewMode) {
+                radioButton('displayModes', id);
+                viewMode = id;
+                doRadioAction(id);
+            }
+        });
+    }
+
+    function doRadioAction(id) {
+        showAllLayers();
+        if (id === 'showPkt') {
+            showPacketLayer();
+        } else if (id === 'showOpt') {
+            showOpticalLayer();
+        }
+    }
+
+    function showAllLayers() {
+        network.node.classed('inactive', false);
+        network.link.classed('inactive', false);
+        d3.selectAll('svg .port').classed('inactive', false);
+        d3.selectAll('svg .portText').classed('inactive', false);
+    }
+
+    function showPacketLayer() {
+        network.node.each(function(d) {
+            // deactivate nodes that are not hosts or switches
+            if (d.class === 'device' && d.type !== 'switch') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        network.link.each(function(lnk) {
+            // deactivate infrastructure links that have opt's as endpoints
+            if (lnk.source.type === 'roadm' || lnk.target.type === 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        // deactivate non-packet ports
+        d3.selectAll('svg .optPort').classed('inactive', true)
+    }
+
+    function showOpticalLayer() {
+        network.node.each(function(d) {
+            // deactivate nodes that are not optical devices
+            if (d.type !== 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        network.link.each(function(lnk) {
+            // deactivate infrastructure links that have opt's as endpoints
+            if (lnk.source.type !== 'roadm' || lnk.target.type !== 'roadm') {
+                d3.select(this).classed('inactive', true);
+            }
+        });
+
+        // deactivate non-packet ports
+        d3.selectAll('svg .pktPort').classed('inactive', true)
+    }
+
+    function setUpKeyHandler() {
+        d3.select('body')
+            .on('keydown', function () {
+                processKeyEvent();
+                if (debug('showKeyHandler')) {
+                    network.svg.append('text')
+                        .attr('x', 5)
+                        .attr('y', 15)
+                        .style('font-size', '20pt')
+                        .text('keyCode: ' + d3.event.keyCode +
+                            ' applied to : ' + contextLabel())
+                        .transition().duration(2000)
+                        .style('font-size', '2pt')
+                        .style('fill-opacity', 0.01)
+                        .remove();
+                }
+            });
+    }
+
+    function contextLabel() {
+        return hovered === null ? "(nothing)" : hovered.id;
+    }
+
+    function radioButton(group, id) {
+        d3.selectAll("#" + group + " .radio").classed("active", false);
+        d3.select("#" + group + " #" + id).classed("active", true);
+    }
+
+    function processKeyEvent() {
+        var code = d3.event.keyCode;
+        switch (code) {
+            case 66:    // B
+                toggleBackground();
+                break;
+            case 71:    // G
+                cycleLayout();
+                break;
+            case 76:    // L
+                cycleLabels();
+                break;
+            case 80:    // P
+                togglePorts();
+                break;
+            case 85:    // U
+                unpin();
+                break;
+        }
+
+    }
+
+    function toggleBackground() {
+        var bg = d3.select('#bg'),
+            vis = bg.style('visibility'),
+            newvis = (vis === 'hidden') ? 'visible' : 'hidden';
+        bg.style('visibility', newvis);
+    }
+
+    function cycleLayout() {
+        config.options.layering = !config.options.layering;
+        network.force.resume();
+    }
+
+    function cycleLabels() {
+        console.log('Cycle Labels - context = ' + contextLabel());
+    }
+
+    function togglePorts() {
+        portLabelsOn = !portLabelsOn;
+        var portVis = portLabelsOn ? 'visible' : 'hidden';
+        d3.selectAll('.port').style('visibility', portVis);
+        d3.selectAll('.portText').style('visibility', portVis);
+    }
+
+    function unpin() {
+        if (hovered) {
+            hovered.fixed = false;
+            findNodeFromData(hovered).classed('fixed', false);
+            network.force.resume();
+        }
+        console.log('Unpin - context = ' + contextLabel());
+    }
+
+
+    // ========================================================
+
+    function drawNetwork() {
+        $('#view').empty();
+
+        prepareNodesAndLinks();
+        createLayout();
+        console.log("\n\nHere is the augmented network object...");
+        console.log(network);
+    }
+
+    function prepareNodesAndLinks() {
+        network.lookup = {};
+        network.nodes = [];
+        network.links = [];
+
+        var nw = network.forceWidth,
+            nh = network.forceHeight;
+
+        function yPosConstraintForNode(n) {
+            return config.constraints.ypos[n.type || 'host'];
+        }
+
+        // Note that both 'devices' and 'hosts' get mapped into the nodes array
+
+        // first, the devices...
+        network.data.devices.forEach(function(n) {
+            var ypc = yPosConstraintForNode(n),
+                ix = Math.random() * 0.6 * nw + 0.2 * nw,
+                iy = ypc * nh,
+                node = {
+                    id: n.id,
+                    labels: n.labels,
+                    class: 'device',
+                    icon: 'device',
+                    type: n.type,
+                    x: ix,
+                    y: iy,
+                    constraint: {
+                        weight: 0.7,
+                        y: iy
+                    }
+                };
+            network.lookup[n.id] = node;
+            network.nodes.push(node);
+        });
+
+        // then, the hosts...
+        network.data.hosts.forEach(function(n) {
+            var ypc = yPosConstraintForNode(n),
+                ix = Math.random() * 0.6 * nw + 0.2 * nw,
+                iy = ypc * nh,
+                node = {
+                    id: n.id,
+                    labels: n.labels,
+                    class: 'host',
+                    icon: 'host',
+                    type: n.type,
+                    x: ix,
+                    y: iy,
+                    constraint: {
+                        weight: 0.7,
+                        y: iy
+                    }
+                };
+            network.lookup[n.id] = node;
+            network.nodes.push(node);
+        });
+
+
+        // now, process the explicit links...
+        network.data.links.forEach(function(lnk) {
+            var src = network.lookup[lnk.src],
+                dst = network.lookup[lnk.dst],
+                id = src.id + "-" + dst.id;
+
+            var link = {
+                class: 'infra',
+                id: id,
+                type: lnk.type,
+                width: lnk.linkWidth,
+                source: src,
+                srcPort: lnk.srcPort,
+                target: dst,
+                tgtPort: lnk.dstPort,
+                strength: config.force.linkStrength.infra
+            };
+            network.links.push(link);
+        });
+
+        // finally, infer host links...
+        network.data.hosts.forEach(function(n) {
+            var src = network.lookup[n.id],
+                dst = network.lookup[n.cp.device],
+                id = src.id + "-" + dst.id;
+
+            var link = {
+                class: 'host',
+                id: id,
+                type: 'hostLink',
+                width: config.hostLinkWidth,
+                source: src,
+                target: dst,
+                strength: config.force.linkStrength.host
+            };
+            network.links.push(link);
+        });
+    }
+
+    function createLayout() {
+
+        var cfg = config.force;
+
+        network.force = d3.layout.force()
+            .size([network.forceWidth, network.forceHeight])
+            .nodes(network.nodes)
+            .links(network.links)
+            .linkStrength(function(d) { return cfg.linkStrength[d.class]; })
+            .linkDistance(function(d) { return cfg.linkDistance[d.class]; })
+            .charge(function(d) { return cfg.charge[d.class]; })
+            .on('tick', tick);
+
+        network.svg = d3.select('#view').append('svg')
+            .attr('width', netView.width)
+            .attr('height', netView.height)
+            .append('g')
+            .attr('transform', config.force.translate());
+//            .attr('id', 'zoomable')
+//            .call(d3.behavior.zoom().on("zoom", zoomRedraw));
+
+        network.svg.append('svg:image')
+            .attr({
+                id: 'bg',
+                width: netView.width,
+                height: netView.height,
+                'xlink:href': config.backgroundUrl
+            })
+            .style('visibility',
+                    config.options.loadBackground ? 'visible' : 'hidden');
+
+//        function zoomRedraw() {
+//            d3.select("#zoomable").attr("transform",
+//                    "translate(" + d3.event.translate + ")"
+//                    + " scale(" + d3.event.scale + ")");
+//        }
+
+        // TODO: move glow/blur stuff to util script
+        var glow = network.svg.append('filter')
+            .attr('x', '-50%')
+            .attr('y', '-50%')
+            .attr('width', '200%')
+            .attr('height', '200%')
+            .attr('id', 'blue-glow');
+
+        glow.append('feColorMatrix')
+            .attr('type', 'matrix')
+            .attr('values', '0 0 0 0  0 ' +
+                '0 0 0 0  0 ' +
+                '0 0 0 0  .7 ' +
+                '0 0 0 1  0 ');
+
+        glow.append('feGaussianBlur')
+            .attr('stdDeviation', 3)
+            .attr('result', 'coloredBlur');
+
+        glow.append('feMerge').selectAll('feMergeNode')
+            .data(['coloredBlur', 'SourceGraphic'])
+            .enter().append('feMergeNode')
+            .attr('in', String);
+
+        // TODO: legend (and auto adjust on scroll)
+//        $('#view').on('scroll', function() {
+//
+//        });
+
+
+        // TODO: move drag behavior into separate method.
+        // == define node drag behavior...
+        network.draggedThreshold = d3.scale.linear()
+            .domain([0, 0.1])
+            .range([5, 20])
+            .clamp(true);
+
+        function dragged(d) {
+            var threshold = network.draggedThreshold(network.force.alpha()),
+                dx = d.oldX - d.px,
+                dy = d.oldY - d.py;
+            if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
+                d.dragged = true;
+            }
+            return d.dragged;
+        }
+
+        network.drag = d3.behavior.drag()
+            .origin(function(d) { return d; })
+            .on('dragstart', function(d) {
+                d.oldX = d.x;
+                d.oldY = d.y;
+                d.dragged = false;
+                d.fixed |= 2;
+            })
+            .on('drag', function(d) {
+                d.px = d3.event.x;
+                d.py = d3.event.y;
+                if (dragged(d)) {
+                    if (!network.force.alpha()) {
+                        network.force.alpha(.025);
+                    }
+                }
+            })
+            .on('dragend', function(d) {
+                if (!dragged(d)) {
+                    selectObject(d, this);
+                }
+                d.fixed &= ~6;
+
+                // once we've finished moving, pin the node in position,
+                // if it is a device (not a host)
+                if (d.class === 'device') {
+                    d.fixed = true;
+                    d3.select(this).classed('fixed', true)
+                }
+            });
+
+        $('#view').on('click', function(e) {
+            if (!$(e.target).closest('.node').length) {
+                deselectObject();
+            }
+        });
+
+        // ...............................................................
+
+        // add links to the display
+        network.link = network.svg.append('g').attr('id', 'links')
+            .selectAll('.link')
+            .data(network.force.links(), function(d) {return d.id})
+            .enter().append('line')
+            .attr('class', function(d) {return 'link ' + d.class});
+
+        network.linkSrcPort = network.svg.append('g')
+            .attr({
+                id: 'srcPorts',
+                class: 'portLayer'
+            });
+        network.linkTgtPort = network.svg.append('g')
+            .attr({
+                id: 'tgtPorts',
+                class: 'portLayer'
+            });
+
+        var portVis = portLabelsOn ? 'visible' : 'hidden',
+            pw = config.labels.port.width,
+            ph = config.labels.port.height;
+
+        network.link.filter('.infra').each(function(d) {
+            var srcType = d.source.type === 'roadm' ? 'optPort' : 'pktPort',
+                tgtType = d.target.type === 'roadm' ? 'optPort' : 'pktPort';
+
+            if (d.source.type)
+
+            network.linkSrcPort.append('rect').attr({
+                id: 'srcPort-' + safeId(d.id),
+                class: 'port ' + srcType,
+                width: pw,
+                height: ph,
+                rx: 4,
+                ry: 4
+            }).style('visibility', portVis);
+
+            network.linkTgtPort.append('rect').attr({
+                id: 'tgtPort-' + safeId(d.id),
+                class: 'port ' + tgtType,
+                width: pw,
+                height: ph,
+                rx: 4,
+                ry: 4
+            }).style('visibility', portVis);
+
+            network.linkSrcPort.append('text').attr({
+                id: 'srcText-' + safeId(d.id),
+                class: 'portText ' + srcType
+            }).text(d.srcPort)
+                .style('visibility', portVis);
+
+            network.linkTgtPort.append('text').attr({
+                id: 'tgtText-' + safeId(d.id),
+                class: 'portText ' + tgtType
+            }).text(d.tgtPort)
+                .style('visibility', portVis);
+        });
+
+        // ...............................................................
+
+        // add nodes to the display
+        network.node = network.svg.selectAll('.node')
+            .data(network.force.nodes(), function(d) {return d.id})
+            .enter().append('g')
+            .attr('class', function(d) {
+                var cls = 'node ' + d.class;
+                if (d.type) {
+                    cls += ' ' + d.type;
+                }
+                return cls;
+            })
+            .attr('transform', function(d) {
+                return translate(d.x, d.y);
+            })
+            .call(network.drag)
+            .on('mouseover', function(d) {
+                // TODO: show tooltip
+                if (network.mouseoutTimeout) {
+                    clearTimeout(network.mouseoutTimeout);
+                    network.mouseoutTimeout = null;
+                }
+                hoverObject(d);
+            })
+            .on('mouseout', function(d) {
+                // TODO: hide tooltip
+                if (network.mouseoutTimeout) {
+                    clearTimeout(network.mouseoutTimeout);
+                    network.mouseoutTimeout = null;
+                }
+                network.mouseoutTimeout = setTimeout(function() {
+                    hoverObject(null);
+                }, config.mouseOutTimerDelayMs);
+            });
+
+
+        // deal with device nodes first
+        network.nodeRect = network.node.filter('.device')
+            .append('rect')
+            .attr({
+                rx: 5,
+                ry: 5,
+                width: 100,
+                height: 12
+            });
+            // note that width/height are adjusted to fit the label text
+            // then padded, and space made for the icon.
+
+        network.node.filter('.device').each(function(d) {
+            var node = d3.select(this),
+                icon = iconUrl(d);
+
+            node.append('text')
+            // TODO: add label cycle behavior
+                .text(d.id)
+                .attr('dy', '1.1em');
+
+            if (icon) {
+                var cfg = config.icons;
+                node.append('svg:image')
+                    .attr({
+                        width: cfg.w,
+                        height: cfg.h,
+                        'xlink:href': icon
+                    });
+                // note, icon relative positioning (x,y) is done after we have
+                // adjusted the bounds of the rectangle...
+            }
+
+            // debug function to show the modelled x,y coordinates of nodes...
+            if (debug('showNodeXY')) {
+                node.select('rect').attr('fill-opacity', 0.5);
+                node.append('circle')
+                    .attr({
+                        class: 'debug',
+                        cx: 0,
+                        cy: 0,
+                        r: '3px'
+                    });
+            }
+        });
+
+        // now process host nodes
+        network.nodeCircle = network.node.filter('.host')
+            .append('circle')
+            .attr({
+                r: config.hostRadius
+            });
+
+        network.node.filter('.host').each(function(d) {
+            var node = d3.select(this),
+                icon = iconUrl(d);
+
+            // debug function to show the modelled x,y coordinates of nodes...
+            if (debug('showNodeXY')) {
+                node.select('circle').attr('fill-opacity', 0.5);
+                node.append('circle')
+                    .attr({
+                        class: 'debug',
+                        cx: 0,
+                        cy: 0,
+                        r: '3px'
+                    });
+            }
+        });
+
+        // this function is scheduled to happen soon after the given thread ends
+        setTimeout(function() {
+            var lab = config.labels,
+                portGap = lab.port.gap,
+                midW = portGap + lab.port.width/ 2,
+                midH = portGap + lab.port.height / 2;
+
+            // post process the device nodes, to pad their size to fit the
+            // label text and attach the icon to the right location.
+            network.node.filter('.device').each(function(d) {
+                // for every node, recompute size, padding, etc. so text fits
+                var node = d3.select(this),
+                    text = node.select('text'),
+                    box = adjustRectToFitText(node);
+
+                // now make the computed adjustment
+                node.select('rect')
+                    .attr(box);
+
+                node.select('image')
+                    .attr('x', box.x + config.icons.xoff)
+                    .attr('y', box.y + config.icons.yoff);
+
+                var bounds = boundsFromBox(box),
+                    portBounds = {
+                        x1: bounds.x1 - midW,
+                        x2: bounds.x2 + midW,
+                        y1: bounds.y1 - midH,
+                        y2: bounds.y2 + midH
+                    };
+
+                // todo: clean up extent and edge work..
+                d.extent = {
+                    left: bounds.x1 - lab.marginLR,
+                    right: bounds.x2 + lab.marginLR,
+                    top: bounds.y1 - lab.marginTB,
+                    bottom: bounds.y2 + lab.marginTB
+                };
+
+                d.edge = {
+                    left   : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x1, bounds.y2),
+                    right  : new geo.LineSegment(bounds.x2, bounds.y1, bounds.x2, bounds.y2),
+                    top    : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x2, bounds.y1),
+                    bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2)
+                };
+
+                d.portEdge = {
+                    left   : new geo.LineSegment(
+                        portBounds.x1, portBounds.y1, portBounds.x1, portBounds.y2
+                    ),
+                    right  : new geo.LineSegment(
+                        portBounds.x2, portBounds.y1, portBounds.x2, portBounds.y2
+                    ),
+                    top    : new geo.LineSegment(
+                        portBounds.x1, portBounds.y1, portBounds.x2, portBounds.y1
+                    ),
+                    bottom : new geo.LineSegment(
+                        portBounds.x1, portBounds.y2, portBounds.x2, portBounds.y2
+                    )
+                };
+
+            });
+
+            network.numTicks = 0;
+            network.preventCollisions = false;
+            network.force.start();
+            for (var i = 0; i < config.force.ticksWithoutCollisions; i++) {
+                network.force.tick();
+            }
+            network.preventCollisions = true;
+            $('#view').css('visibility', 'visible');
+        });
+
+
+        // returns the newly computed bounding box of the rectangle
+        function adjustRectToFitText(n) {
+            var text = n.select('text'),
+                box = text.node().getBBox(),
+                lab = config.labels;
+
+            // not sure why n.data() returns an array of 1 element...
+            var data = n.data()[0];
+
+            text.attr('text-anchor', 'middle')
+                .attr('y', '-0.8em')
+                .attr('x', lab.imgPad/2)
+            ;
+
+            // translate the bbox so that it is centered on [x,y]
+            box.x = -box.width / 2;
+            box.y = -box.height / 2;
+
+            // add padding
+            box.x -= (lab.padLR + lab.imgPad/2);
+            box.width += lab.padLR * 2 + lab.imgPad;
+            box.y -= lab.padTB;
+            box.height += lab.padTB * 2;
+
+            return box;
+        }
+
+        function boundsFromBox(box) {
+            return {
+                x1: box.x,
+                y1: box.y,
+                x2: box.x + box.width,
+                y2: box.y + box.height
+            };
+        }
+
+    }
+
+    function iconUrl(d) {
+        return 'img/' + d.type + '.png';
+//        return config.iconUrl[d.icon];
+    }
+
+    function translate(x, y) {
+        return 'translate(' + x + ',' + y + ')';
+    }
+
+    // prevents collisions amongst device nodes
+    function preventCollisions() {
+        var quadtree = d3.geom.quadtree(network.nodes),
+            hrad = config.hostRadius;
+
+        network.nodes.forEach(function(n) {
+            var nx1, nx2, ny1, ny2;
+
+            if (n.class === 'device') {
+                nx1 = n.x + n.extent.left;
+                nx2 = n.x + n.extent.right;
+                ny1 = n.y + n.extent.top;
+                ny2 = n.y + n.extent.bottom;
+
+            } else {
+                nx1 = n.x - hrad;
+                nx2 = n.x + hrad;
+                ny1 = n.y - hrad;
+                ny2 = n.y + hrad;
+            }
+
+            quadtree.visit(function(quad, x1, y1, x2, y2) {
+                if (quad.point && quad.point !== n) {
+                    // check if the rectangles/circles intersect
+                    var p = quad.point,
+                        px1, px2, py1, py2, ix;
+
+                    if (p.class === 'device') {
+                        px1 = p.x + p.extent.left;
+                        px2 = p.x + p.extent.right;
+                        py1 = p.y + p.extent.top;
+                        py2 = p.y + p.extent.bottom;
+
+                    } else {
+                        px1 = p.x - hrad;
+                        px2 = p.x + hrad;
+                        py1 = p.y - hrad;
+                        py2 = p.y + hrad;
+                    }
+
+                    ix = (px1 <= nx2 && nx1 <= px2 && py1 <= ny2 && ny1 <= py2);
+
+                    if (ix) {
+                        var xa1 = nx2 - px1, // shift n left , p right
+                            xa2 = px2 - nx1, // shift n right, p left
+                            ya1 = ny2 - py1, // shift n up   , p down
+                            ya2 = py2 - ny1, // shift n down , p up
+                            adj = Math.min(xa1, xa2, ya1, ya2);
+
+                        if (adj == xa1) {
+                            n.x -= adj / 2;
+                            p.x += adj / 2;
+                        } else if (adj == xa2) {
+                            n.x += adj / 2;
+                            p.x -= adj / 2;
+                        } else if (adj == ya1) {
+                            n.y -= adj / 2;
+                            p.y += adj / 2;
+                        } else if (adj == ya2) {
+                            n.y += adj / 2;
+                            p.y -= adj / 2;
+                        }
+                    }
+                    return ix;
+                }
+            });
+
+        });
+    }
+
+    function tick(e) {
+        network.numTicks++;
+
+        if (config.options.layering) {
+            // adjust the y-coord of each node, based on y-pos constraints
+            network.nodes.forEach(function (n) {
+                var z = e.alpha * n.constraint.weight;
+                if (!isNaN(n.constraint.y)) {
+                    n.y = (n.constraint.y * z + n.y * (1 - z));
+                }
+            });
+        }
+
+        if (config.options.collisionPrevention && network.preventCollisions) {
+            preventCollisions();
+        }
+
+        var portHalfW = config.labels.port.width / 2,
+            portHalfH = config.labels.port.height / 2;
+
+        // clip visualization of links at bounds of nodes...
+        network.link.each(function(d) {
+            var xs = d.source.x,
+                ys = d.source.y,
+                xt = d.target.x,
+                yt = d.target.y,
+                line = new geo.LineSegment(xs, ys, xt, yt),
+                e, ix,
+                exs, eys, ext, eyt,
+                pxs, pys, pxt, pyt;
+
+            if (d.class === 'host') {
+                // no adjustment for source end of link, since hosts are dots
+                exs = xs;
+                eys = ys;
+
+            } else {
+                for (e in d.source.edge) {
+                    ix = line.intersect(d.source.edge[e].offset(xs, ys));
+                    if (ix.in1 && ix.in2) {
+                        exs = ix.x;
+                        eys = ix.y;
+
+                        // also pick off the port label intersection
+                        ix = line.intersect(d.source.portEdge[e].offset(xs, ys));
+                        pxs = ix.x;
+                        pys = ix.y;
+                        break;
+                    }
+                }
+            }
+
+            for (e in d.target.edge) {
+                ix = line.intersect(d.target.edge[e].offset(xt, yt));
+                if (ix.in1 && ix.in2) {
+                    ext = ix.x;
+                    eyt = ix.y;
+
+                    // also pick off the port label intersection
+                    ix = line.intersect(d.target.portEdge[e].offset(xt, yt));
+                    pxt = ix.x;
+                    pyt = ix.y;
+                    break;
+                }
+            }
+
+            // adjust the endpoints of the link's line to match rectangles
+            var sid = safeId(d.id);
+            d3.select(this)
+                .attr('x1', exs)
+                .attr('y1', eys)
+                .attr('x2', ext)
+                .attr('y2', eyt);
+
+            d3.select('#srcPort-' + sid)
+                .attr('x', pxs - portHalfW)
+                .attr('y', pys - portHalfH);
+
+            d3.select('#tgtPort-' + sid)
+                .attr('x', pxt - portHalfW)
+                .attr('y', pyt - portHalfH);
+
+            // TODO: fit label rect to size of port number.
+            d3.select('#srcText-' + sid)
+                .attr('x', pxs - 5)
+                .attr('y', pys + 3);
+
+            d3.select('#tgtText-' + sid)
+                .attr('x', pxt - 5)
+                .attr('y', pyt + 3);
+
+        });
+
+        // position each node by translating the node (group) by x,y
+        network.node
+            .attr('transform', function(d) {
+                return translate(d.x, d.y);
+            });
+
+    }
+
+    //    $('#docs-close').on('click', function() {
+    //        deselectObject();
+    //        return false;
+    //    });
+
+    //    $(document).on('click', '.select-object', function() {
+    //        var obj = graph.data[$(this).data('name')];
+    //        if (obj) {
+    //            selectObject(obj);
+    //        }
+    //        return false;
+    //    });
+
+    function findNodeFromData(d) {
+        var el = null;
+        network.node.filter('.' + d.class).each(function(n) {
+            if (n.id === d.id) {
+                el = d3.select(this);
+            }
+        });
+        return el;
+    }
+
+    function selectObject(obj, el) {
+        var node;
+        if (el) {
+            node = d3.select(el);
+        } else {
+            network.node.each(function(d) {
+                if (d == obj) {
+                    node = d3.select(el = this);
+                }
+            });
+        }
+        if (!node) return;
+
+        if (node.classed('selected')) {
+            deselectObject();
+            flyinPane(null);
+            return;
+        }
+        deselectObject(false);
+
+        selected = {
+            obj : obj,
+            el  : el
+        };
+
+        node.classed('selected', true);
+        flyinPane(obj);
+    }
+
+    function deselectObject(doResize) {
+        // Review: logic of 'resize(...)' function.
+        if (doResize || typeof doResize == 'undefined') {
+            resize(false);
+        }
+
+        // deselect all nodes in the network...
+        network.node.classed('selected', false);
+        selected = {};
+        flyinPane(null);
+    }
+
+    function flyinPane(obj) {
+        var pane = d3.select('#flyout'),
+            url;
+
+        if (obj) {
+            // go get details of the selected object from the server...
+            url = detailJsonUrl(obj.id);
+            d3.json(url, function (err, data) {
+                if (err) {
+                    alert('Oops! Error reading JSON...\n\n' +
+                        'URL: ' + url + '\n\n' +
+                        'Error: ' + err.message);
+                    return;
+                }
+//                console.log("JSON data... " + url);
+//                console.log(data);
+
+                displayDetails(data, pane);
+            });
+
+        } else {
+            // hide pane
+            pane.transition().duration(750)
+                .style('right', '-320px')
+                .style('opacity', 0.0);
+        }
+    }
+
+    function displayDetails(data, pane) {
+        $('#flyout').empty();
+
+        var title = pane.append("h2"),
+            table = pane.append("table"),
+            tbody = table.append("tbody");
+
+        $('<img src="img/' + data.type + '.png">').appendTo(title);
+        $('<span>').attr('class', 'icon').text(data.id).appendTo(title);
+
+
+        // TODO: consider using d3 data bind to TR/TD
+
+        data.propOrder.forEach(function(p) {
+            if (p === '-') {
+                addSep(tbody);
+            } else {
+                addProp(tbody, p, data.props[p]);
+            }
+        });
+
+        function addSep(tbody) {
+            var tr = tbody.append('tr');
+            $('<hr>').appendTo(tr.append('td').attr('colspan', 2));
+        }
+
+        function addProp(tbody, label, value) {
+            var tr = tbody.append('tr');
+
+            tr.append('td')
+                .attr('class', 'label')
+                .text(label + ' :');
+
+            tr.append('td')
+                .attr('class', 'value')
+                .text(value);
+        }
+
+        // show pane
+        pane.transition().duration(750)
+            .style('right', '20px')
+            .style('opacity', 1.0);
+    }
+
+    function highlightObject(obj) {
+        if (obj) {
+            if (obj != highlighted) {
+                // TODO set or clear "inactive" class on nodes, based on criteria
+                network.node.classed('inactive', function(d) {
+                    //                return (obj !== d &&
+                    //                    d.relation(obj.id));
+                    return (obj !== d);
+                });
+                // TODO: same with links
+                network.link.classed('inactive', function(d) {
+                    return (obj !== d.source && obj !== d.target);
+                });
+            }
+            highlighted = obj;
+        } else {
+            if (highlighted) {
+                // clear the inactive flag (no longer suppressed visually)
+                network.node.classed('inactive', false);
+                network.link.classed('inactive', false);
+            }
+            highlighted = null;
+
+        }
+    }
+
+    function hoverObject(obj) {
+        if (obj) {
+            hovered = obj;
+        } else {
+            if (hovered) {
+                hovered = null;
+            }
+        }
+    }
+
+
+    function resize() {
+        netView.height = window.innerHeight - config.mastHeight;
+        netView.width = window.innerWidth;
+        $('#view')
+            .css('height', netView.height + 'px')
+            .css('width', netView.width + 'px');
+
+        network.forceWidth = netView.width - config.force.marginLR;
+        network.forceHeight = netView.height - config.force.marginTB;
+    }
+
+    // ======================================================================
+    // register with the UI framework
+
+    onos.ui.addView('topo', {
+        load: loadNetworkView
+    });
+
+
+}(ONOS));
+