Another step forward with the UI.
- Added hosts to test data.
- Messed with colors and icons.
- Added more internal configuration values.
diff --git a/web/gui/src/main/webapp/network.js b/web/gui/src/main/webapp/network.js
index 80d11b7..ef190e7 100644
--- a/web/gui/src/main/webapp/network.js
+++ b/web/gui/src/main/webapp/network.js
@@ -10,17 +10,33 @@
     var api = onos.api;
 
     var config = {
-            layering: false,
+            options: {
+                layering: false,
+                collisionPrevention: true
+            },
             jsonUrl: 'network.json',
             iconUrl: {
-                pkt: 'pkt.png',
-                opt: 'opt.png'
+                logo: 'img/onos-logo.tiff',
+                device: 'img/device.png',
+                host: 'img/host.png',
+                pkt: 'img/pkt.png',
+                opt: 'img/opt.png'
             },
             mastHeight: 32,
             force: {
-                linkDistance: 240,
-                linkStrength: 0.8,
-                charge: -400,
+                note: 'node.class or link.class is used to differentiate',
+                linkDistance: {
+                    infra: 240,
+                    host: 100
+                },
+                linkStrength: {
+                    infra: 1.0,
+                    host: 0.4
+                },
+                charge: {
+                    device: -800,
+                    host: -400
+                },
                 ticksWithoutCollisions: 50,
                 marginLR: 20,
                 marginTB: 20,
@@ -37,12 +53,21 @@
                 marginLR: 3,
                 marginTB: 2
             },
+            icons: {
+                w: 32,
+                h: 32,
+                xoff: -12,
+                yoff: -10
+            },
             constraints: {
                 ypos: {
-                    pkt: 0.3,
-                    opt: 0.7
+                    host: 0.15,
+                    switch: 0.3,
+                    roadm: 0.7
                 }
-            }
+            },
+            hostLinkWidth: 1.0,
+            mouseOutTimerDelayMs: 120
         },
         view = {},
         network = {},
@@ -104,14 +129,23 @@
         var nw = network.forceWidth,
             nh = network.forceHeight;
 
-        network.data.nodes.forEach(function(n) {
+        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,
-                    status: n.status,
                     x: ix,
                     y: iy,
                     constraint: {
@@ -123,21 +157,61 @@
             network.nodes.push(node);
         });
 
-        function yPosConstraintForNode(n) {
-            return config.constraints.ypos[n.type] || 0.5;
-        }
+        // 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(n) {
             var src = network.lookup[n.src],
                 dst = network.lookup[n.dst],
                 id = src.id + "~" + dst.id;
 
             var link = {
+                class: 'infra',
                 id: id,
+                type: n.type,
+                width: n.linkWidth,
                 source: src,
                 target: dst,
-                strength: config.force.linkStrength
+                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);
         });
@@ -145,13 +219,15 @@
 
     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 d.strength; })
-            .size([network.forceWidth, network.forceHeight])
-            .linkDistance(config.force.linkDistance)
-            .charge(config.force.charge)
+            .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')
@@ -205,9 +281,10 @@
         network.link = network.svg.append('g').selectAll('.link')
             .data(network.force.links(), function(d) {return d.id})
             .enter().append('line')
-            .attr('class', 'link');
+            .attr('class', function(d) {return 'link ' + d.class});
 
-        // TODO: drag behavior
+
+        // == define node drag behavior...
         network.draggedThreshold = d3.scale.linear()
             .domain([0, 0.1])
             .range([5, 20])
@@ -258,7 +335,11 @@
             .data(network.force.nodes(), function(d) {return d.id})
             .enter().append('g')
             .attr('class', function(d) {
-                return 'node ' + d.type;
+                var cls = 'node ' + d.class;
+                if (d.type) {
+                    cls += ' ' + d.type;
+                }
+                return cls;
             })
             .attr('transform', function(d) {
                 return translate(d.x, d.y);
@@ -281,29 +362,32 @@
                     }
                     network.mouseoutTimeout = setTimeout(function() {
                         highlightObject(null);
-                    }, 160);
+                    }, config.mouseOutTimerDelayMs);
                 }
             });
 
         network.nodeRect = network.node.append('rect')
             .attr('rx', 5)
-            .attr('ry', 5)
-            .attr('width', 126)
-            .attr('height', 40);
+            .attr('ry', 5);
+        // note that width/height are adjusted to fit the label text
 
         network.node.each(function(d) {
             var node = d3.select(this),
                 rect = node.select('rect'),
-                img = node.append('svg:image')
-                    .attr('x', -16)
-                    .attr('y', -16)
-                    .attr('width', 32)
-                    .attr('height', 32)
-                    .attr('xlink:href', iconUrl(d)),
+                icon = iconUrl(d),
                 text = node.append('text')
                     .text(d.id)
-                    .attr('dy', '1.1em'),
-                dummy;
+                    .attr('dy', '1.1em');
+
+            if (icon) {
+                var cfg = config.icons;
+                node.append('svg:image')
+                    .attr('width', cfg.w)
+                    .attr('height', cfg.h)
+                    .attr('xlink:href', icon);
+                // note, icon relative positioning (x,y) is done after we have
+                // adjusted the bounds of the rectangle...
+            }
 
         });
 
@@ -352,7 +436,8 @@
                     .attr('height', bounds.y2 - bounds.y1);
 
                 node.select('image')
-                    .attr('x', bounds.x1);
+                    .attr('x', bounds.x1 + config.icons.xoff)
+                    .attr('y', bounds.y1 + config.icons.yoff);
 
                 d.extent = {
                     left: bounds.x1 - lab.marginLR,
@@ -384,7 +469,7 @@
     }
 
     function iconUrl(d) {
-        return config.iconUrl[d.type];
+        return config.iconUrl[d.icon];
     }
 
     function translate(x, y) {
@@ -440,7 +525,7 @@
     function tick(e) {
         network.numTicks++;
 
-        if (config.layering) {
+        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;
@@ -450,7 +535,7 @@
             });
         }
 
-        if (network.preventCollisions) {
+        if (config.options.collisionPrevention && network.preventCollisions) {
             preventCollisions();
         }
 
diff --git a/web/gui/src/main/webapp/network.json b/web/gui/src/main/webapp/network.json
index b4f1b6e..c43e0ef 100644
--- a/web/gui/src/main/webapp/network.json
+++ b/web/gui/src/main/webapp/network.json
@@ -1,56 +1,163 @@
 {
-    "id": "network-v1",
     "meta": {
-        "__comment_1__": "This is sample data for developing the ONOS UI",
-        "foo": "bar",
-        "zoo": "goo"
+        "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..."
     },
-    "nodes": [
+    "devices": [
         {
-            "id": "sample1",
-            "type": "opt",
-            "status": "good"
+            "id": "of:0000000000000001",
+            "labels": ["00:00:00:00:00:00:00:01", "of/::01", "opt-1"],
+            "type": "roadm"
         },
         {
-            "id": "00:00:00:00:00:00:00:02",
-            "type": "opt",
-            "status": "good"
+            "id": "of:0000000000000002",
+            "labels": ["00:00:00:00:00:00:00:02", "of/::02", "opt-2"],
+            "type": "roadm"
         },
         {
-            "id": "00:00:00:00:00:00:00:03",
-            "type": "opt",
-            "status": "good"
+            "id": "of:0000000000000003",
+            "labels": ["00:00:00:00:00:00:00:03", "of/::03", "opt-3"],
+            "type": "roadm"
         },
         {
-            "id": "00:00:00:00:00:00:00:04",
-            "type": "opt",
-            "status": "good"
+            "id": "of:0000000000000004",
+            "labels": ["00:00:00:00:00:00:00:04", "of/::04", "opt-4"],
+            "type": "roadm"
         },
         {
-            "id": "00:00:00:00:00:00:00:11",
-            "type": "pkt",
-            "status": "good"
+            "id": "of:0000000000000011",
+            "labels": ["00:00:00:00:00:00:00:11", "of/::11", "pkt-11"],
+            "type": "switch"
         },
         {
-            "id": "00:00:00:00:00:00:00:12",
-            "type": "pkt",
-            "status": "good"
+            "id": "of:0000000000000012",
+            "labels": ["00:00:00:00:00:00:00:12", "of/::12", "pkt-12"],
+            "type": "switch"
         },
         {
-            "id": "00:00:00:00:00:00:00:13",
-            "type": "pkt",
-            "status": "good"
+            "id": "of:0000000000000013",
+            "labels": ["00:00:00:00:00:00:00:13", "of/::13", "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": "sample1", "dst": "00:00:00:00:00:00:00:02" },
-        { "src": "sample1", "dst": "00:00:00:00:00:00:00:03" },
-        { "src": "sample1", "dst": "00:00:00:00:00:00:00:04" },
-        { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:03" },
-        { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:04" },
-        { "src": "00:00:00:00:00:00:00:03", "dst": "00:00:00:00:00:00:00:04" },
-        { "src": "00:00:00:00:00:00:00:13", "dst": "00:00:00:00:00:00:00:03" },
-        { "src": "00:00:00:00:00:00:00:12", "dst": "00:00:00:00:00:00:00:02" },
-        { "src": "00:00:00:00:00:00:00:11", "dst": "sample1" }
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000002",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000003",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000001",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000002",
+            "dst": "of:0000000000000003",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000002",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000003",
+            "dst": "of:0000000000000004",
+            "type": "optical",
+            "linkWidth": 1.5
+        },
+        {
+            "src": "of:0000000000000013",
+            "dst": "of:0000000000000003",
+            "type": "direct",
+            "linkWidth": 1.0
+        },
+        {
+            "src": "of:0000000000000012",
+            "dst": "of:0000000000000002",
+            "type": "direct",
+            "linkWidth": 1.0
+        },
+        {
+            "src": "of:0000000000000011",
+            "dst": "of:0000000000000001",
+            "type": "direct",
+            "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/onos.css b/web/gui/src/main/webapp/onos.css
index 340ae79..b2df75c 100644
--- a/web/gui/src/main/webapp/onos.css
+++ b/web/gui/src/main/webapp/onos.css
@@ -38,7 +38,7 @@
  * Network Graph elements ======================================
  */
 
-.link {
+svg .link {
     fill: none;
     stroke: #666;
     stroke-width: 1.5px;
@@ -56,7 +56,7 @@
     stroke-width: 1.5px;
 }
 
-.node rect {
+svg .node rect {
     stroke-width: 1.5px;
 
     transition: opacity 250ms;
@@ -64,13 +64,15 @@
     -moz-transition: opacity 250ms;
 }
 
-/*differentiate between packet and optical nodes*/
-svg .node.pkt rect {
-    fill: #77a;
+svg .node.device.roadm rect {
+    fill: #229;
+}
+svg .node.device.switch rect {
+    fill: #55f;
 }
 
-svg .node.opt rect {
-    fill: #7a7;
+svg .node.host rect {
+    fill: #787;
 }
 
 svg .node text {
@@ -121,15 +123,13 @@
 #frame {
     width: 100%;
     height: 100%;
-    background-color: #cdf;
+    background-color: #fff;
 }
 
 #mast {
     height: 32px;
-    background-color: #abe;
+    padding: 6px;
+    background-color: #ccc;
     vertical-align: baseline;
 }
 
-#main {
-    background-color: #99c;
-}
diff --git a/web/gui/src/main/webapp/opt.png b/web/gui/src/main/webapp/opt.png
deleted file mode 100644
index 2f2c88e..0000000
--- a/web/gui/src/main/webapp/opt.png
+++ /dev/null
Binary files differ
diff --git a/web/gui/src/main/webapp/pkt.png b/web/gui/src/main/webapp/pkt.png
deleted file mode 100644
index 1b1d5a3..0000000
--- a/web/gui/src/main/webapp/pkt.png
+++ /dev/null
Binary files differ