Topo2: Add grid (x,y) option to null-provider devices and hosts (and basic element config).

Change-Id: Ia9eed66bda03174a6986d07fec40eb2a8f7728e3
diff --git a/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java b/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java
index 295995f..65a2783 100644
--- a/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java
@@ -17,8 +17,8 @@
 
 /**
  * Basic configuration for network elements, e.g. devices, hosts. Such elements
- * can have a friendly name, geo-coordinates, logical rack coordinates and
- * an owner entity.
+ * can have a friendly name, geo-coordinates (or grid-coordinates),
+ * logical rack coordinates and an owner entity.
  */
 public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> {
 
@@ -33,6 +33,11 @@
     public static final String UI_TYPE = "uiType";
 
     /**
+     * Key for location type (geo or grid).
+     */
+    public static final String LOC_TYPE = "locType";
+
+    /**
      * Key for latitude.
      */
     public static final String LATITUDE = "latitude";
@@ -43,6 +48,17 @@
     public static final String LONGITUDE = "longitude";
 
     /**
+     * Key for grid X coordinate.
+     */
+    public static final String GRID_X = "gridx";
+
+    /**
+     * Key for grid Y coordinate.
+     */
+    public static final String GRID_Y = "gridy";
+
+
+    /**
      * Key for rack address.
      */
     protected static final String RACK_ADDRESS = "rackAddress";
@@ -58,6 +74,8 @@
     protected static final double ZERO_THRESHOLD = Double.MIN_VALUE * 2.0;
 
     private static final double DEFAULT_COORD = 0.0;
+    private static final String LOC_TYPE_GEO = "geo";
+    private static final String LOC_TYPE_GRID = "grid";
 
     /**
      * Returns friendly label for the element. If not set, returns the
@@ -101,6 +119,28 @@
         return (BasicElementConfig) setOrClear(UI_TYPE, uiType);
     }
 
+    /**
+     * Returns the location type (geo or grid) for the element in
+     * the Topology View. If not set, returns the default of "geo".
+     *
+     * @return location type (string)
+     */
+    public String locType() {
+        return get(LOC_TYPE, LOC_TYPE_GEO);
+    }
+
+    /**
+     * Sets the location type (geo or grid) for the element in
+     * the Topology View. If null is passsed, it will default to "geo".
+     *
+     * @param locType the UI type; null for default
+     * @return self
+     */
+    public BasicElementConfig locType(String locType) {
+        String lt = LOC_TYPE_GRID.equals(locType) ? LOC_TYPE_GRID : LOC_TYPE_GEO;
+        return (BasicElementConfig) setOrClear(LOC_TYPE, lt);
+    }
+
     private boolean doubleIsZero(double value) {
         return value >= -ZERO_THRESHOLD && value <= ZERO_THRESHOLD;
     }
@@ -156,6 +196,44 @@
     }
 
     /**
+     * Returns element grid x-coordinate.
+     *
+     * @return element x-coordinate
+     */
+    public double gridX() {
+        return get(GRID_X, DEFAULT_COORD);
+    }
+
+    /**
+     * Sets the element grid x-coordinate.
+     *
+     * @param x new x-coordinate; null to clear
+     * @return self
+     */
+    public BasicElementConfig gridX(Double x) {
+        return (BasicElementConfig) setOrClear(GRID_X, x);
+    }
+
+    /**
+     * Returns element grid y-coordinate.
+     *
+     * @return element y-coordinate
+     */
+    public double gridY() {
+        return get(GRID_Y, DEFAULT_COORD);
+    }
+
+    /**
+     * Sets the element grid y-coordinate.
+     *
+     * @param y new y-coordinate; null to clear
+     * @return self
+     */
+    public BasicElementConfig gridY(Double y) {
+        return (BasicElementConfig) setOrClear(GRID_Y, y);
+    }
+
+    /**
      * Returns the element rack address.
      *
      * @return rack address; null if not set
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/BasicElementConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/BasicElementConfigTest.java
index 8c750ff..f81f462 100644
--- a/core/api/src/test/java/org/onosproject/net/config/basics/BasicElementConfigTest.java
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/BasicElementConfigTest.java
@@ -33,6 +33,8 @@
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     private static final String E1 = "e1";
+    private static final String GEO = "geo";
+    private static final String GRID = "grid";
 
     // concrete subclass of abstract class we are testing
     private static class ElmCfg extends BasicElementConfig<String> {
@@ -104,4 +106,46 @@
         print(cfg);
         assertEquals("not other type", "someOtherType", cfg.uiType());
     }
+
+    @Test
+    public void defaultGridCoords() {
+        print(cfg);
+        assertEquals("gridx", 0.0, cfg.gridX(), ZERO_THRESHOLD);
+        assertEquals("gridy", 0.0, cfg.gridY(), ZERO_THRESHOLD);
+    }
+
+    @Test
+    public void someGridCoords() {
+        cfg.gridX(35.0).gridY(49.7);
+        print(cfg);
+        assertEquals("gridx", 35.0, cfg.gridX(), ZERO_THRESHOLD);
+        assertEquals("gridy", 49.7, cfg.gridY(), ZERO_THRESHOLD);
+    }
+
+    @Test
+    public void defaultLocationType() {
+        print(cfg);
+        assertEquals("not geo", GEO, cfg.locType());
+    }
+
+    @Test
+    public void geoLocationType() {
+        cfg.locType(GEO);
+        print(cfg);
+        assertEquals("not geo", GEO, cfg.locType());
+    }
+
+    @Test
+    public void gridLocationType() {
+        cfg.locType(GRID);
+        print(cfg);
+        assertEquals("not grid", GRID, cfg.locType());
+    }
+
+    @Test
+    public void otherLocationType() {
+        cfg.locType("foobar");
+        print(cfg);
+        assertEquals("not geo", GEO, cfg.locType());
+    }
 }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
index 3b81d4d..431bcd3 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullDevice.java
@@ -32,6 +32,8 @@
 @Command(scope = "onos", name = "null-create-device",
         description = "Adds a simulated device to the custom topology simulation")
 public class CreateNullDevice extends AbstractShellCommand {
+    private static final String GEO = "geo";
+    private static final String GRID = "grid";
 
     @Argument(index = 0, name = "type", description = "Device type, e.g. switch, roadm",
             required = true, multiValued = false)
@@ -45,13 +47,19 @@
             required = true, multiValued = false)
     Integer portCount = null;
 
-    @Argument(index = 3, name = "latitude", description = "Geo latitude",
+    @Argument(index = 3, name = "latOrY",
+            description = "Geo latitude / Grid y-coord",
             required = true, multiValued = false)
-    Double latitude = null;
+    Double latOrY = null;
 
-    @Argument(index = 4, name = "longitude", description = "Geo longitude",
+    @Argument(index = 4, name = "longOrX",
+            description = "Geo longitude / Grid x-coord",
             required = true, multiValued = false)
-    Double longitude = null;
+    Double longOrX = null;
+
+    @Argument(index = 5, name = "locType", description = "Location type {geo|grid}",
+            required = false, multiValued = false)
+    String locType = GEO;
 
     @Override
     protected void execute() {
@@ -64,13 +72,23 @@
             return;
         }
 
+        if (!(GEO.equals(locType) || GRID.equals(locType))) {
+            error("locType must be 'geo' or 'grid'.");
+            return;
+        }
+
         CustomTopologySimulator sim = (CustomTopologySimulator) simulator;
         DeviceId deviceId = sim.nextDeviceId();
         BasicDeviceConfig cfg = cfgService.addConfig(deviceId, BasicDeviceConfig.class);
         cfg.name(name)
-                .latitude(latitude)
-                .longitude(longitude)
-                .apply();
+                .locType(locType);
+
+        if (GEO.equals(locType)) {
+            cfg.latitude(latOrY).longitude(longOrX);
+        } else {
+            cfg.gridX(longOrX).gridY(latOrY);
+        }
+        cfg.apply();
 
         sim.createDevice(deviceId, name, Device.Type.valueOf(type.toUpperCase()), portCount);
     }
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
index 26bca8c..ee4c835 100644
--- a/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/cli/CreateNullHost.java
@@ -40,6 +40,8 @@
 @Command(scope = "onos", name = "null-create-host",
         description = "Adds a simulated end-station host to the custom topology simulation")
 public class CreateNullHost extends AbstractShellCommand {
+    private static final String GEO = "geo";
+    private static final String GRID = "grid";
 
     @Argument(index = 0, name = "deviceName", description = "Name of device where host is attached",
             required = true, multiValued = false)
@@ -49,13 +51,19 @@
             required = true, multiValued = false)
     String hostIp = null;
 
-    @Argument(index = 2, name = "latitude", description = "Geo latitude",
+    @Argument(index = 2, name = "latOrY",
+            description = "Geo latitude / Grid y-coord",
             required = true, multiValued = false)
-    Double latitude = null;
+    Double latOrY = null;
 
-    @Argument(index = 3, name = "longitude", description = "Geo longitude",
+    @Argument(index = 3, name = "longOrX",
+            description = "Geo longitude / Grid x-coord",
             required = true, multiValued = false)
-    Double longitude = null;
+    Double longOrX = null;
+
+    @Argument(index = 4, name = "locType", description = "Location type {geo|grid}",
+            required = false, multiValued = false)
+    String locType = GEO;
 
     @Override
     protected void execute() {
@@ -68,14 +76,25 @@
             return;
         }
 
+        if (!(GEO.equals(locType) || GRID.equals(locType))) {
+            error("locType must be 'geo' or 'grid'.");
+            return;
+        }
+
         CustomTopologySimulator sim = (CustomTopologySimulator) simulator;
         DeviceId deviceId = sim.deviceId(deviceName);
         HostId id = sim.nextHostId();
         HostLocation location = findAvailablePort(deviceId);
         BasicHostConfig cfg = cfgService.addConfig(id, BasicHostConfig.class);
-        cfg.latitude(latitude)
-                .longitude(longitude)
-                .apply();
+
+        cfg.locType(locType);
+
+        if (GEO.equals(locType)) {
+            cfg.latitude(latOrY).longitude(longOrX);
+        } else {
+            cfg.gridX(longOrX).gridY(latOrY);
+        }
+        cfg.apply();
 
         sim.createHost(id, location, IpAddress.valueOf(hostIp));
     }
diff --git a/tools/test/topos/regions-bayarea-grid.sh b/tools/test/topos/regions-bayarea-grid.sh
new file mode 100755
index 0000000..2c700c4
--- /dev/null
+++ b/tools/test/topos/regions-bayarea-grid.sh
@@ -0,0 +1,289 @@
+#!/bin/bash
+#
+# A test topology of four data centers (spine-leaf fabrics), configured as
+# four sub-regions, and positioned in the Bay Area (geographically speaking).
+#
+# Script Configuration:
+#
+# host     : the controller instance against which this script is run
+# nports   : the number of ports to configure on each switch
+# sleepfor : the number of seconds to wait for sim to restart
+
+host=${1:-127.0.0.1}
+nports=16
+sleepfor=5
+
+### start up null provider
+
+onos ${host} null-simulation stop custom
+onos ${host} wipe-out please
+onos ${host} null-simulation start custom
+
+
+## unfortunately, it takes a time for the sim to start up
+#  this is not ideal...
+
+echo
+echo "Sleeping while sim starts up... (${sleepfor} seconds)..."
+echo
+sleep ${sleepfor}
+
+
+### Add devices and links
+#
+# null-create-device <type> <name> <#ports> <latitude/Y> <longitude/X> [geo|grid]
+# null-create-link <type> <src> <dst>
+
+onos ${host} <<-EOF
+
+# root region
+
+# CO 1
+null-create-device switch SPINE-A-1 ${nports} 10.0 20.0 grid
+null-create-device switch SPINE-A-2 ${nports} 10.0 50.0 grid
+null-create-device switch SPINE-A-3 ${nports} 10.0 80.0 grid
+null-create-device switch SPINE-A-4 ${nports} 10.0 110.0 grid
+
+null-create-device switch LEAF-A-1 ${nports} 45.0 20.0 grid
+null-create-device switch LEAF-A-2 ${nports} 45.0 50.0 grid
+null-create-device switch LEAF-A-3 ${nports} 45.0 80.0 grid
+null-create-device switch LEAF-A-4 ${nports} 45.0 110.0 grid
+
+# Links in CO 1
+null-create-link direct LEAF-A-1 SPINE-A-1
+null-create-link direct LEAF-A-1 SPINE-A-2
+null-create-link direct LEAF-A-1 SPINE-A-3
+null-create-link direct LEAF-A-1 SPINE-A-4
+
+null-create-link direct LEAF-A-2 SPINE-A-1
+null-create-link direct LEAF-A-2 SPINE-A-2
+null-create-link direct LEAF-A-2 SPINE-A-3
+null-create-link direct LEAF-A-2 SPINE-A-4
+
+null-create-link direct LEAF-A-3 SPINE-A-1
+null-create-link direct LEAF-A-3 SPINE-A-2
+null-create-link direct LEAF-A-3 SPINE-A-3
+null-create-link direct LEAF-A-3 SPINE-A-4
+
+null-create-link direct LEAF-A-4 SPINE-A-1
+null-create-link direct LEAF-A-4 SPINE-A-2
+null-create-link direct LEAF-A-4 SPINE-A-3
+null-create-link direct LEAF-A-4 SPINE-A-4
+
+# CO 2
+null-create-device switch SPINE-B-1 ${nports} 37.458236 -122.252604
+null-create-device switch SPINE-B-2 ${nports} 37.458236 -122.212604
+null-create-device switch SPINE-B-3 ${nports} 37.458236 -122.172604
+null-create-device switch SPINE-B-4 ${nports} 37.458236 -122.132604
+
+null-create-device switch LEAF-B-1 ${nports} 37.418236 -122.252604
+null-create-device switch LEAF-B-2 ${nports} 37.418236 -122.212604
+null-create-device switch LEAF-B-3 ${nports} 37.418236 -122.172604
+null-create-device switch LEAF-B-4 ${nports} 37.418236 -122.132604
+
+# Links in CO 2
+null-create-link direct LEAF-B-1 SPINE-B-1
+null-create-link direct LEAF-B-1 SPINE-B-2
+null-create-link direct LEAF-B-1 SPINE-B-3
+null-create-link direct LEAF-B-1 SPINE-B-4
+
+null-create-link direct LEAF-B-2 SPINE-B-1
+null-create-link direct LEAF-B-2 SPINE-B-2
+null-create-link direct LEAF-B-2 SPINE-B-3
+null-create-link direct LEAF-B-2 SPINE-B-4
+
+null-create-link direct LEAF-B-3 SPINE-B-1
+null-create-link direct LEAF-B-3 SPINE-B-2
+null-create-link direct LEAF-B-3 SPINE-B-3
+null-create-link direct LEAF-B-3 SPINE-B-4
+
+null-create-link direct LEAF-B-4 SPINE-B-1
+null-create-link direct LEAF-B-4 SPINE-B-2
+null-create-link direct LEAF-B-4 SPINE-B-3
+null-create-link direct LEAF-B-4 SPINE-B-4
+
+# CO 3
+null-create-device switch SPINE-C-1 ${nports} 37.338208 -121.926329
+null-create-device switch SPINE-C-2 ${nports} 37.338208 -121.886329
+null-create-device switch SPINE-C-3 ${nports} 37.338208 -121.846329
+null-create-device switch SPINE-C-4 ${nports} 37.338208 -121.806329
+
+null-create-device switch LEAF-C-1 ${nports} 37.298208 -121.926329
+null-create-device switch LEAF-C-2 ${nports} 37.298208 -121.886329
+null-create-device switch LEAF-C-3 ${nports} 37.298208 -121.846329
+null-create-device switch LEAF-C-4 ${nports} 37.298208 -121.806329
+
+# Links in CO 3
+null-create-link direct LEAF-C-1 SPINE-C-1
+null-create-link direct LEAF-C-1 SPINE-C-2
+null-create-link direct LEAF-C-1 SPINE-C-3
+null-create-link direct LEAF-C-1 SPINE-C-4
+
+null-create-link direct LEAF-C-2 SPINE-C-1
+null-create-link direct LEAF-C-2 SPINE-C-2
+null-create-link direct LEAF-C-2 SPINE-C-3
+null-create-link direct LEAF-C-2 SPINE-C-4
+
+null-create-link direct LEAF-C-3 SPINE-C-1
+null-create-link direct LEAF-C-3 SPINE-C-2
+null-create-link direct LEAF-C-3 SPINE-C-3
+null-create-link direct LEAF-C-3 SPINE-C-4
+
+null-create-link direct LEAF-C-4 SPINE-C-1
+null-create-link direct LEAF-C-4 SPINE-C-2
+null-create-link direct LEAF-C-4 SPINE-C-3
+null-create-link direct LEAF-C-4 SPINE-C-4
+
+# CO 4
+null-create-device switch SPINE-D-1 ${nports} 37.556826 -122.051926
+null-create-device switch SPINE-D-2 ${nports} 37.556826 -122.011926
+null-create-device switch SPINE-D-3 ${nports} 37.556826 -121.971926
+null-create-device switch SPINE-D-4 ${nports} 37.556826 -121.931926
+
+null-create-device switch LEAF-D-1 ${nports} 37.516826 -122.051926
+null-create-device switch LEAF-D-2 ${nports} 37.516826 -122.011926
+null-create-device switch LEAF-D-3 ${nports} 37.516826 -121.971926
+null-create-device switch LEAF-D-4 ${nports} 37.516826 -121.931926
+
+# Links in CO 4
+null-create-link direct LEAF-D-1 SPINE-D-1
+null-create-link direct LEAF-D-1 SPINE-D-2
+null-create-link direct LEAF-D-1 SPINE-D-3
+null-create-link direct LEAF-D-1 SPINE-D-4
+
+null-create-link direct LEAF-D-2 SPINE-D-1
+null-create-link direct LEAF-D-2 SPINE-D-2
+null-create-link direct LEAF-D-2 SPINE-D-3
+null-create-link direct LEAF-D-2 SPINE-D-4
+
+null-create-link direct LEAF-D-3 SPINE-D-1
+null-create-link direct LEAF-D-3 SPINE-D-2
+null-create-link direct LEAF-D-3 SPINE-D-3
+null-create-link direct LEAF-D-3 SPINE-D-4
+
+null-create-link direct LEAF-D-4 SPINE-D-1
+null-create-link direct LEAF-D-4 SPINE-D-2
+null-create-link direct LEAF-D-4 SPINE-D-3
+null-create-link direct LEAF-D-4 SPINE-D-4
+
+# Inter-CO Links
+null-create-link direct LEAF-A-4 LEAF-B-1
+null-create-link direct LEAF-A-4 LEAF-C-1
+null-create-link direct LEAF-A-4 LEAF-D-4
+null-create-link direct LEAF-B-1 LEAF-C-1
+null-create-link direct LEAF-B-1 LEAF-D-4
+null-create-link direct LEAF-C-1 LEAF-D-4
+
+EOF
+
+### Add a host per device
+#
+# null-create-host <device-id> <host-ip> <latitude/Y> <longitude/X> [geo|grid]
+
+onos ${host} <<-EOF
+
+null-create-host LEAF-A-1 192.168.1.1 60.0 20.0 grid
+null-create-host LEAF-A-2 192.168.2.1 60.0 50.0 grid
+null-create-host LEAF-A-3 192.168.3.1 60.0 80.0 grid
+null-create-host LEAF-A-4 192.168.4.1 60.0 110.0 grid
+
+null-create-host LEAF-B-1 192.168.51.1 37.388236 -122.252604
+null-create-host LEAF-B-2 192.168.52.1 37.388236 -122.212604
+null-create-host LEAF-B-3 192.168.53.1 37.388236 -122.172604
+null-create-host LEAF-B-4 192.168.54.1 37.388236 -122.132604
+
+null-create-host LEAF-C-1 192.168.101.1 37.268208 -121.926329
+null-create-host LEAF-C-2 192.168.102.1 37.268208 -121.886329
+null-create-host LEAF-C-3 192.168.103.1 37.268208 -121.846329
+null-create-host LEAF-C-4 192.168.104.1 37.268208 -121.806329
+
+null-create-host LEAF-D-1 192.168.151.1 37.476826 -122.051926
+null-create-host LEAF-D-2 192.168.152.1 37.476826 -122.011926
+null-create-host LEAF-D-3 192.168.153.1 37.476826 -121.971926
+null-create-host LEAF-D-4 192.168.154.1 37.476826 -121.931926
+
+EOF
+
+### Add regions and associate devices with them
+#
+# region-add <region-id> <region-name> <region-type> <region-master>
+# region-add-devices <region-id> <device-id>...
+
+onos ${host} <<-EOF
+
+region-add c01 SanFrancisco DATA_CENTER 37.75394143914288 -122.45945851660800 ${host}
+region-add c02 PaloAlto     DATA_CENTER 37.45466637790734 -122.21838933304870 ${host}
+region-add c03 SanJose      DATA_CENTER 37.34425619809433 -121.94768095808017 ${host}
+region-add c04 Fremont      DATA_CENTER 37.54328280574901 -122.01205548699211 ${host}
+
+region-add-devices c01 \
+    null:0000000000000001 \
+    null:0000000000000002 \
+    null:0000000000000003 \
+    null:0000000000000004 \
+    null:0000000000000005 \
+    null:0000000000000006 \
+    null:0000000000000007 \
+    null:0000000000000008 \
+
+region-add-devices c02 \
+    null:0000000000000009 \
+    null:000000000000000a \
+    null:000000000000000b \
+    null:000000000000000c \
+    null:000000000000000d \
+    null:000000000000000e \
+    null:000000000000000f \
+    null:0000000000000010 \
+
+region-add-devices c03 \
+    null:0000000000000011 \
+    null:0000000000000012 \
+    null:0000000000000013 \
+    null:0000000000000014 \
+    null:0000000000000015 \
+    null:0000000000000016 \
+    null:0000000000000017 \
+    null:0000000000000018 \
+
+region-add-devices c04 \
+    null:0000000000000019 \
+    null:000000000000001a \
+    null:000000000000001b \
+    null:000000000000001c \
+    null:000000000000001d \
+    null:000000000000001e \
+    null:000000000000001f \
+    null:0000000000000020 \
+
+regions
+
+EOF
+
+### Add layouts, associating backing regions, and optional parent.
+#
+# layout-add <layout-id> <region-id(opt)> <parent-layout-id(opt)>
+
+onos ${host} <<-EOF
+
+layout-add lC01 c01
+layout-add lC02 c02
+layout-add lC03 c03
+layout-add lC04 c04
+
+layouts
+
+EOF
+
+
+### Set up debug log messages for classes we care about
+
+onos ${host} <<-EOF
+
+log:set DEBUG org.onosproject.ui.impl.topo.Topo2ViewMessageHandler
+log:set DEBUG org.onosproject.ui.impl.topo.Topo2Jsonifier
+log:set DEBUG org.onosproject.ui.impl.UiWebSocket
+log:set DEBUG org.onosproject.ui.impl.UiTopoSession
+log:list
+
+EOF
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
index 6234391..8db72aa 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
@@ -364,6 +364,7 @@
         }
     }
 
+    // FIXME: need to handle geo vs. grid location...
     private void addGeoLocation(ObjectNode node, Annotated a) {
         List<String> lngLat = getAnnotValues(a, LONGITUDE, LATITUDE);
         if (lngLat != null) {
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
index 5fa2390..929f1c9 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
@@ -183,7 +183,7 @@
 
                     if (event.memo === 'added') {
                         device = this.model.get('devices').add(event.data);
-                        $log('Added device', device)
+                        $log.debug('Added device', device);
                     } else if (event.memo === 'updated') {
                         device = this.getDevice(event.subject);
                         device.set(event.data);