Merge remote-tracking branch 'origin/master'
diff --git a/apps/tvue/src/main/java/org/onlab/onos/tvue/TopologyResource.java b/apps/tvue/src/main/java/org/onlab/onos/tvue/TopologyResource.java
index 992bbb3..145e94a 100644
--- a/apps/tvue/src/main/java/org/onlab/onos/tvue/TopologyResource.java
+++ b/apps/tvue/src/main/java/org/onlab/onos/tvue/TopologyResource.java
@@ -15,6 +15,7 @@
 import org.onlab.onos.net.topology.TopologyGraph;
 import org.onlab.onos.net.topology.TopologyService;
 import org.onlab.onos.net.topology.TopologyVertex;
+import org.onlab.packet.IPAddress;
 import org.onlab.rest.BaseResource;
 
 import javax.ws.rs.GET;
@@ -54,6 +55,7 @@
         ArrayNode vertexesNode = mapper.createArrayNode();
         for (TopologyVertex vertex : graph.getVertexes()) {
             vertexesNode.add(json(mapper, vertex.deviceId(), 2,
+                                  vertex.deviceId().uri().getSchemeSpecificPart(),
                                   deviceService.isAvailable(vertex.deviceId())));
         }
 
@@ -70,14 +72,17 @@
         // Merge the exterior and interior vertexes and inject host links as
         // the exterior edges.
         for (Host host : hostService.getHosts()) {
-            vertexesNode.add(json(mapper, host.id(), 3, true));
+            Set<IPAddress> ipAddresses = host.ipAddresses();
+            IPAddress ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
+            String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
+            vertexesNode.add(json(mapper, host.id(), 3, label, true));
             edgesNode.add(json(mapper, 1, host.location(), new ConnectPoint(host.id(), portNumber(-1))));
         }
 
         // Now put the vertexes and edges into a root node and ship them off
         ObjectNode rootNode = mapper.createObjectNode();
-        rootNode.put("vertexes", vertexesNode);
-        rootNode.put("edges", edgesNode);
+        rootNode.set("vertexes", vertexesNode);
+        rootNode.set("edges", edgesNode);
         return Response.ok(rootNode.toString()).build();
     }
 
@@ -126,12 +131,12 @@
         return aggLinks;
     }
 
-
     // Produces JSON for a graph vertex.
     private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
-                            boolean isOnline) {
+                            String label, boolean isOnline) {
         return mapper.createObjectNode()
                 .put("name", id.uri().toString())
+                .put("label", label)
                 .put("group", group)
                 .put("online", isOnline);
     }
diff --git a/apps/tvue/src/main/webapp/index.html b/apps/tvue/src/main/webapp/index.html
index 04abfa4..9c551fd 100644
--- a/apps/tvue/src/main/webapp/index.html
+++ b/apps/tvue/src/main/webapp/index.html
@@ -129,7 +129,7 @@
         }
 
         function dragstart(d) {
-            d3.select(this).classed("fixed", d.fixed = true);
+            // d3.select(this).classed("fixed", d.fixed = true);
         }
 
 
@@ -147,8 +147,8 @@
                     }
                     return false;
                 }
-                node = {"id": vertex.name, "group": vertex.group,
-                    "online": vertex.online, "stamp": stamp};
+                node = {"id": vertex.name, "label": vertex.label,
+                    "group": vertex.group, "online": vertex.online, "stamp": stamp};
                 nodes.push(node);
                 topo.vertexes[vertex.name] = node;
                 update();
@@ -239,6 +239,8 @@
                             targetNode = aux;
                         } else if (d3.event.keyCode == 70) {
                             nextPath();
+                        } else if (d3.event.keyCode == 67 && selectedNode) {
+                            selectedNode.fixed = !selectedNode.fixed;
                         }
 
                         d3.selectAll(".nodeStrokeClass").attr("fill", fillColor);
@@ -288,7 +290,7 @@
                         .attr("class", "textClass")
                         .attr("x", 20)
                         .attr("y", ".31em")
-                        .text(function (d) { return d.id; });
+                        .text(function (d) { return d.label; });
 
                 node.exit().remove();
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
index 724051f..85d5680 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
@@ -4,12 +4,17 @@
 
 /**
  * Service for injecting flow rules into the environment and for obtaining
- * information about flow rules already in the environment.
+ * information about flow rules already in the environment. This implements
+ * semantics of a distributed authoritative flow table where the master copy
+ * of the flow rules lies with the controller and the devices hold only the
+ * 'cached' copy.
  */
 public interface FlowRuleService {
 
     /**
      * Returns the collection of flow entries applied on the specified device.
+     * This will include flow rules which may not yet have been applied to
+     * the device.
      *
      * @param deviceId device identifier
      * @return collection of flow rules
@@ -17,7 +22,9 @@
     Iterable<FlowEntry> getFlowEntries(DeviceId deviceId);
 
     /**
-     * Applies the specified flow rules onto their respective devices.
+     * Applies the specified flow rules onto their respective devices. These
+     * flow rules will be retained by the system and re-applied anytime the
+     * device reconnects to the controller.
      *
      * @param flowRules one or more flow rules
      * throws SomeKindOfException that indicates which ones were applied and
@@ -26,7 +33,9 @@
     void applyFlowRules(FlowRule... flowRules);
 
     /**
-     * Removes the specified flow rules from their respective devices.
+     * Removes the specified flow rules from their respective devices. If the
+     * device is not presently connected to the controller, these flow will
+     * be removed once the device reconnects.
      *
      * @param flowRules one or more flow rules
      * throws SomeKindOfException that indicates which ones were removed and
@@ -34,6 +43,10 @@
      */
     void removeFlowRules(FlowRule... flowRules);
 
+
+    // void addInitialFlowContributor(InitialFlowContributor contributor);
+    // void removeInitialFlowContributor(InitialFlowContributor contributor);
+
     /**
      * Adds the specified flow rule listener.
      *
diff --git a/features/features.xml b/features/features.xml
index 10f63bd..d96b2fd 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -39,27 +39,27 @@
 
     <feature name="onos-rest" version="1.0.0"
              description="ONOS REST API components">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <feature>onos-thirdparty-web</feature>
         <bundle>mvn:org.onlab.onos/onos-rest/1.0.0-SNAPSHOT</bundle>
     </feature>
 
     <feature name="onos-gui" version="1.0.0"
              description="ONOS GUI console components">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <feature>onos-thirdparty-web</feature>
         <bundle>mvn:org.onlab.onos/onos-gui/1.0.0-SNAPSHOT</bundle>
     </feature>
 
     <feature name="onos-cli" version="1.0.0"
              description="ONOS admin command console components">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <bundle>mvn:org.onlab.onos/onos-cli/1.0.0-SNAPSHOT</bundle>
     </feature>
 
     <feature name="onos-openflow" version="1.0.0"
             description="ONOS OpenFlow API, Controller &amp; Providers">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
 
         <bundle>mvn:org.onlab.onos/onos-of-api/1.0.0-SNAPSHOT</bundle>
@@ -74,14 +74,14 @@
 
     <feature name="onos-app-tvue" version="1.0.0"
              description="ONOS sample topology viewer application">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <feature>onos-thirdparty-web</feature>
         <bundle>mvn:org.onlab.onos/onos-app-tvue/1.0.0-SNAPSHOT</bundle>
     </feature>
     
     <feature name="onos-app-fwd" version="1.0.0"
              description="ONOS sample forwarding application">
-        <feature>onos-core</feature>
+        <feature>onos-api</feature>
         <bundle>mvn:org.onlab.onos/onos-app-fwd/1.0.0-SNAPSHOT</bundle>
     </feature>
 
diff --git a/tools/package/bin/onos-ctl b/tools/package/bin/onos-ctl
new file mode 100755
index 0000000..2c6097d
--- /dev/null
+++ b/tools/package/bin/onos-ctl
@@ -0,0 +1,8 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Starts ONOS Apache Karaf container
+#-------------------------------------------------------------------------------
+
+cd $(dirname $0)/../apache-karaf-*/bin
+./karaf "$@"
+
diff --git a/tools/package/package b/tools/package/package
new file mode 100755
index 0000000..870acc6
--- /dev/null
+++ b/tools/package/package
@@ -0,0 +1,59 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Packages ONOS distributable into onos.tar.gz
+#-------------------------------------------------------------------------------
+
+export M2_REPO=${M2_REPO:-~/.m2/repository}
+export KARAF_ZIP=${KARAF_ZIP:-~/Downloads/apache-karaf-3.0.1.zip}
+export KARAF_DIST=$(basename $KARAF_ZIP .zip)
+
+export ONOS_VERSION=${ONOS_VERSION:-1.0.0-SNAPSHOT}
+export ONOS_STAGE_ROOT=${ONOS_STAGE_ROOT:-/tmp}
+export ONOS_BITS=onos-$ONOS_VERSION
+export ONOS_STAGE=$ONOS_STAGE_ROOT/$ONOS_BITS
+
+# Bail on any errors
+set -e
+
+rm -fr $ONOS_STAGE # Remove this when package script is completed
+
+# Make sure we have the original apache karaf bits first
+[ ! -d $M2_REPO ] && echo "M2 repository $M2_REPO not found" && exit 1
+[ ! -f $KARAF_ZIP ] && echo "Apache Karaf bits $KARAF_ZIP not found" && exit 1
+[ -d $ONOS_STAGE ] && echo "ONOS stage $ONOS_STAGE already exists" && exit 1
+
+# Create the stage directory and warp into it
+mkdir -p $ONOS_STAGE
+cd $ONOS_STAGE
+
+# Unroll the Apache Karaf bits and make the ONOS top-level directories.
+unzip $KARAF_ZIP
+mkdir bin
+mkdir lib
+
+# Stage the ONOS admin scripts
+cp -r $ONOS_ROOT/tools/package/bin .
+
+# Stage the ONOS bundles
+mkdir -p lib/org/onlab 
+cp -r $M2_REPO/org/onlab lib/org
+
+
+# Patch the Apache Karaf distribution file to point to the lib as maven repo
+#perl -pi.old -e "s|^org.ops4j.pax.url.mvn.repositories= |org.ops4j.pax.url.mvn.repositories= \\\n    file:../../lib, |" $ONOS_STAGE/$KARAF_DIST/etc/org.ops4j.pax.url.mvn.cfg
+
+# Patch the Apache Karaf distribution file to add ONOS features repository
+perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-features/$ONOS_VERSION/xml/features|" \
+    $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg 
+
+# Patch the Apache Karaf distribution file to load ONOS features
+perl -pi.old -e 's|^(featuresBoot=.*)|\1,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-tvue|' \
+    /tmp/onos-1.0.0-SNAPSHOT/apache-karaf-3.0.1/etc/org.apache.karaf.features.cfg 
+
+# Patch the Apache Karaf distribution with ONOS branding bundle
+cp $M2_REPO/org/onlab/onos/onos-branding/$ONOS_VERSION/onos-branding-*.jar \
+    $ONOS_STAGE/apache-karaf-*/lib
+
+# Now package up the ONOS tar file
+cd $ONOS_STAGE_ROOT
+tar zcf $ONOS_BITS.tar.gz $ONOS_BITS