You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/08/25 15:06:12 UTC

[15/17] incubator-tinkerpop git commit: Revert "Revert "Merge remote-tracking branch 'origin' into tp30""

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/conf/remote-objects.yaml
----------------------------------------------------------------------
diff --git a/gremlin-console/conf/remote-objects.yaml b/gremlin-console/conf/remote-objects.yaml
index 78424fd..f507f4e 100644
--- a/gremlin-console/conf/remote-objects.yaml
+++ b/gremlin-console/conf/remote-objects.yaml
@@ -15,6 +15,27 @@
 # specific language governing permissions and limitations
 # under the License.
 
+##############################################################
+# This configuration is meant to have Gremlin Server return
+# Gryo serialized objects. The TinkerGraph IoRegistry is
+# assigned as this is the configuration defined in the
+# pre-packaged Gremlin Server configuration files.  The
+# client configuration for serializers should match server.
+# Note that the server configures this via the
+# useMapperFromGraph setting - that simply means to use
+# the registry of the current configured Graph when
+# serializing and for these the pre-packaged purpose,
+# that's TinkerGraph.
+#
+# This file will work with:
+# - gremlin-server.yaml
+# - gremlin-server-classic.yaml
+# - gremlin-server-modern.yaml
+# - gremlin-server-modern-readonly.yaml
+# - gremlin-server-secure.yaml
+##############################################################
+
 hosts: [localhost]
 port: 8182
-serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0}
\ No newline at end of file
+serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0,
+              config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistry] }}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/conf/remote-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-console/conf/remote-secure.yaml b/gremlin-console/conf/remote-secure.yaml
index 3e1deae..4f8d22b 100644
--- a/gremlin-console/conf/remote-secure.yaml
+++ b/gremlin-console/conf/remote-secure.yaml
@@ -15,6 +15,15 @@
 # specific language governing permissions and limitations
 # under the License.
 
+##############################################################
+# This configuration is meant to have Gremlin Server return
+# text serialized objects. The server will toString()
+# results giving a view into how scripts are executing.
+#
+# This file will work with:
+# - gremlin-server-secure.yaml
+##############################################################
+
 hosts: [localhost]
 port: 8182
 username: stephen

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/conf/remote.yaml
----------------------------------------------------------------------
diff --git a/gremlin-console/conf/remote.yaml b/gremlin-console/conf/remote.yaml
index 7b23779..c181591 100644
--- a/gremlin-console/conf/remote.yaml
+++ b/gremlin-console/conf/remote.yaml
@@ -15,6 +15,18 @@
 # specific language governing permissions and limitations
 # under the License.
 
+##############################################################
+# This configuration is meant to have Gremlin Server return
+# text serialized objects. The server will toString()
+# results giving a view into how scripts are executing.
+#
+# This file will work with:
+# - gremlin-server.yaml
+# - gremlin-server-classic.yaml
+# - gremlin-server-modern.yaml
+# - gremlin-server-modern-readonly.yaml
+##############################################################
+
 hosts: [localhost]
 port: 8182
 serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-console/pom.xml b/gremlin-console/pom.xml
index 5e3210a..f2a2e9d 100644
--- a/gremlin-console/pom.xml
+++ b/gremlin-console/pom.xml
@@ -21,7 +21,7 @@ limitations under the License.
     <parent>
         <artifactId>tinkerpop</artifactId>
         <groupId>org.apache.tinkerpop</groupId>
-        <version>3.0.1-SNAPSHOT</version>
+        <version>3.1.0-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-console</artifactId>
     <name>Apache TinkerPop :: Gremlin Console</name>

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiRemoteAcceptor.groovy
----------------------------------------------------------------------
diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiRemoteAcceptor.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiRemoteAcceptor.groovy
index 69dfcda..b8872e9 100644
--- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiRemoteAcceptor.groovy
+++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiRemoteAcceptor.groovy
@@ -21,15 +21,20 @@ package org.apache.tinkerpop.gremlin.console.plugin
 import groovy.transform.CompileStatic
 import org.apache.tinkerpop.gremlin.groovy.plugin.RemoteAcceptor
 import org.apache.tinkerpop.gremlin.groovy.plugin.RemoteException
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal
+import org.apache.tinkerpop.gremlin.process.traversal.Path
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
+import org.apache.tinkerpop.gremlin.structure.Direction
 import org.apache.tinkerpop.gremlin.structure.Edge
 import org.apache.tinkerpop.gremlin.structure.Graph
 import org.apache.tinkerpop.gremlin.structure.Vertex
 import groovy.json.JsonSlurper
 import groovyx.net.http.HTTPBuilder
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils
 import org.codehaus.groovy.tools.shell.Groovysh
 import org.codehaus.groovy.tools.shell.IO
+import org.javatuples.Pair
+
+import java.util.stream.Collectors
 
 import static groovyx.net.http.ContentType.JSON
 
@@ -46,11 +51,15 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
     private final Groovysh shell
     private final IO io
 
-    private long vizStepDelay
+    boolean traversalSubmittedForViz = false
+    long vizStepDelay
     private float[] vizStartRGBColor
+    private float[] vizDefaultRGBColor
     private char vizColorToFade
     private float vizColorFadeRate
-    private Map<String, Float> fadingVertexColors;
+    private float vizStartSize
+    private float vizSizeDecrementRate
+    private Map vertexAttributes = [:]
 
     public GephiRemoteAcceptor(final Groovysh shell, final IO io) {
         this.shell = shell
@@ -59,8 +68,11 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
         // traversal visualization defaults
         vizStepDelay = 1000;                 // 1 second pause between viz of steps
         vizStartRGBColor = [0.0f, 1.0f, 0.5f]  // light aqua green
+        vizDefaultRGBColor = [0.6f, 0.6f, 0.6f]  // light grey
         vizColorToFade = 'g'                 // will fade so blue is strongest
         vizColorFadeRate = 0.7               // the multiplicative rate to fade visited vertices
+        vizStartSize = 20
+        vizSizeDecrementRate = 0.33f
     }
 
     @Override
@@ -79,25 +91,17 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
             }
         }
 
-        String vizConfig = " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " +
-                "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate"
-        if (args.size() >= 4) {
-            if (args.size() > 7) {
-                vizConfig = configVizOptions(args.subList(3, 6))
-            } else {
-                vizConfig = configVizOptions(args.subList(3, args.size()))
-            }
-        }
+        def vizConfig = " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " +
+                "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate, startSize:$vizStartSize," +
+                "sizeDecrementRate:$vizSizeDecrementRate"
 
         return "Connection to Gephi - http://$host:$port/$workspace" + vizConfig
     }
 
     @Override
     Object configure(final List<String> args) throws RemoteException {
-        if (args.size() != 2)
-            throw new RemoteException("Expects [host <hostname>|port <port number>|workspace <name>|" +
-                    "stepDelay <milliseconds>|startRGBColor <RGB array of floats>|" +
-                    "colorToFade: <char r|g|b>]|colorFadeRate: <float>")
+        if (args.size() < 2)
+            throw new RemoteException("Invalid config arguments - check syntax")
 
         if (args[0] == "host")
             host = args[1]
@@ -117,67 +121,25 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
             parseVizColorToFade(args[1])
         else if (args[0] == "colorFadeRate")
             parseVizColorFadeRate(args[1])
-        else
-            throw new RemoteException("Expects [host <hostname>|port <port number>|workspace <name>|" +
-                    "stepDelay <milliseconds>|startRGBColor <RGB array of floats>|" +
-                    "colorToFade: <char r|g|b>]|colorFadeRate: <float>")
+        else if (args[0] == "sizeDecrementRate")
+            parseVizSizeDecrementRate(args[1])
+        else if (args[0] == "startSize")
+            parseVizStartSize(args[1])
+        else if (args[0] == "visualTraversal") {
+            def graphVar = shell.interp.context.getVariable(args[1])
+            if (!(graphVar instanceof Graph))
+                throw new RemoteException("Invalid argument to 'visualTraversal' - first parameter must be a Graph instance")
+
+            def gVar = args.size() == 3 ? args[2] : "vg"
+            def theG = GraphTraversalSource.build().with(new GephiTraversalVisualizationStrategy(this)).create(graphVar)
+            shell.interp.context.setVariable(gVar, theG)
+        } else
+            throw new RemoteException("Invalid config arguments - check syntax")
 
         return "Connection to Gephi - http://$host:$port/$workspace" +
                 " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " +
-                "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate"
-    }
-
-
-    private Object configVizOptions(final List<String> vizConfigArgs) {
-        if (vizConfigArgs.size() >= 1)
-            parseVizStepDelay(vizConfigArgs[0])
-
-        if (vizConfigArgs.size() >= 2)
-            parseVizStartRGBColor(vizConfigArgs[1])
-
-        if (vizConfigArgs.size() >= 3)
-            parseVizColorToFade(vizConfigArgs[2])
-
-        if (vizConfigArgs.size() >= 4)
-            parseVizColorFadeRate(vizConfigArgs[3])
-
-
-        return " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " +
-                "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate"
-    }
-
-    private void parseVizStepDelay(String arg) {
-        try {
-            vizStepDelay = Long.parseLong(arg)
-        } catch (Exception ignored) {
-            throw new RemoteException("The stepDelay must be a long value")
-        }
-    }
-
-    private void parseVizStartRGBColor(String arg) {
-        try {
-            vizStartRGBColor = arg[1..-2].tokenize(',')*.toFloat()
-            assert (vizStartRGBColor.length == 3)
-        } catch (Exception ignored) {
-            throw new RemoteException("The vizStartRGBColor must be an array of 3 float values, e.g. [0.0,1.0,0.5]")
-        }
-    }
-
-    private void parseVizColorToFade(String arg) {
-        try {
-            vizColorToFade = arg.charAt(0).toLowerCase();
-            assert (vizColorToFade == 'r' || vizColorToFade == 'g' || vizColorToFade == 'b')
-        } catch (Exception ignored) {
-            throw new RemoteException("The vizColorToFade must be one character value among: r, g, b, R, G, B")
-        }
-    }
-
-    private void parseVizColorFadeRate(String arg) {
-        try {
-            vizColorFadeRate = Float.parseFloat(arg)
-        } catch (Exception ignored) {
-            throw new RemoteException("The colorFadeRate must be a float value")
-        }
+                "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate, startSize:$vizStartSize," +
+                "sizeDecrementRate:$vizSizeDecrementRate"
     }
 
     @Override
@@ -190,36 +152,70 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
             return
         }
 
+        // need to clear the vertex attributes
+        vertexAttributes.clear()
+
+        // this tells the GraphTraversalVisualizationStrategy that if the line eval's to a traversal it should
+        // try to visualize it
+        traversalSubmittedForViz = true
+
+        // get the colors/sizes back to basics before trying visualize
+        resetColorsSizes()
+
         final Object o = shell.execute(line)
         if (o instanceof Graph) {
             clearGraph()
             def graph = (Graph) o
             def g = graph.traversal()
             g.V().sideEffect { addVertexToGephi(g, it.get()) }.iterate()
-        } else if (o instanceof Traversal.Admin) {
-            fadingVertexColors = [:]
-            def traversal = (Traversal.Admin) o
-            def memKeys = traversal.getSideEffects().keys()
-            def memSize = memKeys.size()
-            // assumes user called store("1")...store("n") in ascension
-            for (int i = 1; i <= memSize; i++) {
-                def stepKey = Integer.toString(i)
-                if (memKeys.contains(stepKey)) {
-                    io.out.print("Visualizing vertices at step: $stepKey... ")
-                    updateVisitedVertices()
-                    int visitedCount = 0
-
-                    if (traversal.getSideEffects().keys().contains(stepKey)) {
-                        traversal.getSideEffects().get(stepKey).get().each { element ->
-                            visitVertexToGephi((Vertex) element)
-                            visitedCount++
+        } else {
+            // an individual Path needs a special case as it is an iterator and gets unrolled by
+            // IteratorUtils.asIterator() if not wrapped in a list prior.
+            final Iterator itty = (o instanceof Path) ? IteratorUtils.asIterator([o]) : IteratorUtils.asIterator(o)
+            def first = true
+            while (itty.hasNext()) {
+                final Object current = itty.next();
+                if (current instanceof Path) {
+                    // paths get returned as iterators - so basically any Iterator that has vertices in it will have
+                    // their path highlighted
+                    final Path path = (Path) current
+                    final List<Vertex> verticesInPath = path.stream().map { Pair pair -> pair.getValue0() }
+                            .filter { Object e -> e instanceof Vertex }.collect(Collectors.toList())
+
+                    for (int ix = 0; ix < verticesInPath.size(); ix++) {
+                        final Vertex v = (Vertex) verticesInPath.get(ix)
+
+                        // if this vertex has already been highlighted in gephi then no need to do it again,
+                        // just update the touch count in memory
+                        if (!vertexAttributes.containsKey(v.id().toString())) {
+                            // this is a new vertex visited so it needs to get highlighted in gephi
+                            visitVertexInGephi(v)
+                            if (ix > 0) {
+                                final Vertex previous = (Vertex) verticesInPath.get(ix - 1)
+                                v.edges(Direction.BOTH).findAll { Edge edge ->
+                                    edge.bothVertices().any { Vertex vertex -> vertex == previous }
+                                }.each { Object edge ->
+                                    visitEdgeInGephi((Edge) edge)
+                                }
+                            }
                         }
+
+                        // need to increment the touch even though this may be the first time passed through
+                        // because the default for touch=1 when it is added to the graph
+                        touch(v)
+                    }
+
+                    if (itty.hasNext() || !first) {
+                        sleep(vizStepDelay)
+                        applyRelativeSizingInGephi()
                     }
-                    io.out.println("Visited: $visitedCount")
+
+                    first = false
                 }
-                sleep(vizStepDelay)
             }
         }
+
+        traversalSubmittedForViz = false
     }
 
     @Override
@@ -227,27 +223,78 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
 
     }
 
-    def updateVisitedVertices() {
-        fadingVertexColors.keySet().each { vertex ->
-            def currentColor = fadingVertexColors.get(vertex)
+    /**
+     * Visits the last set of vertices traversed and degrades their color and size.
+     */
+    def updateVisitedVertices(def List except = []) {
+        vertexAttributes.keySet().findAll{ vertexId -> !except.contains(vertexId) }.each { String vertexId ->
+            def attrs = vertexAttributes[vertexId]
+            float currentColor = attrs.color
             currentColor *= vizColorFadeRate
-            fadingVertexColors.put(vertex, currentColor)
-            def props = [:]
-            props.put(vizColorToFade.toString(), currentColor)
-            updateGephiGraph([cn: [(vertex): props]])
+
+            int currentSize = attrs["size"]
+            currentSize = Math.max(1, currentSize - (currentSize * vizSizeDecrementRate))
+
+            vertexAttributes.get(vertexId).color = currentColor
+            vertexAttributes.get(vertexId).size = currentSize
+
+            changeVertexAttributes(vertexId)
+        }
+    }
+
+    def touch(Vertex v) {
+        vertexAttributes.get(v.id().toString()).touch++
+    }
+
+    def applyRelativeSizingInGephi() {
+        def touches = vertexAttributes.values().collect{it["touch"]}
+        def max = touches.max()
+        def min = touches.min()
+
+        vertexAttributes.each { k, v ->
+            double touch = v.touch
+
+            // establishes the relative size of the node with a lower limit of 0.25 of vizStartSize
+            def relative = Math.max((touch - min) / Math.max((max - min).doubleValue(), 0.00001), 0.25)
+            int size = Math.max(1, vizStartSize * relative)
+            v.size = size
+
+            changeVertexAttributes(k)
         }
     }
 
-    def visitVertexToGephi(def Vertex v) {
+    def changeVertexAttributes(def String vertexId) {
+        def props = [:]
+        props.put(vizColorToFade.toString(), vertexAttributes[vertexId].color)
+        props.put("size", vertexAttributes[vertexId].size)
+        updateGephiGraph([cn: [(vertexId): props]])
+    }
+
+    /**
+     * Visit a vertex traversed and initialize its color and size.
+     */
+    def visitVertexInGephi(def Vertex v, def size = vizStartSize) {
         def props = [:]
         props.put('r', vizStartRGBColor[0])
         props.put('g', vizStartRGBColor[1])
         props.put('b', vizStartRGBColor[2])
-        props.put('x', 1)
+        props.put('size', size)
+        props.put('visited', 1)
 
         updateGephiGraph([cn: [(v.id().toString()): props]])
 
-        fadingVertexColors.put(v.id().toString(), vizStartRGBColor[fadeColorIndex()])
+        vertexAttributes[v.id().toString()] = [color: vizStartRGBColor[fadeColorIndex()], size: size, touch: 1]
+    }
+
+    def visitEdgeInGephi(def Edge e) {
+        def props = [:]
+        props.put('r', vizStartRGBColor[0])
+        props.put('g', vizStartRGBColor[1])
+        props.put('b', vizStartRGBColor[2])
+        props.put('size', vizStartSize)
+        props.put('visited', 1)
+
+        updateGephiGraph([ce: [(e.id().toString()): props]])
     }
 
     def fadeColorIndex() {
@@ -263,6 +310,10 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
         // grab the first property value from the strategies of values
         def props = g.V(v).valueMap().next().collectEntries { kv -> [(kv.key): kv.value[0]] }
         props << [label: v.label()]
+        props.put('r', vizDefaultRGBColor[0])
+        props.put('g', vizDefaultRGBColor[1])
+        props.put('b', vizDefaultRGBColor[2])
+        props.put('visited', 0)
 
         // only add if it does not exist in graph already
         if (!getFromGephiGraph([operation: "getNode", id: v.id().toString()]).isPresent())
@@ -282,6 +333,7 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
         props.put('source', e.outVertex().id().toString())
         props.put('target', e.inVertex().id().toString())
         props.put('directed', true)
+        props.put('visited', 0)
 
         // make sure the in vertex is there but don't add its edges - that will happen later as we are looping
         // all vertices in the graph
@@ -295,6 +347,13 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
         updateGephiGraph([dn: [filter: "ALL"]])
     }
 
+    def resetColorsSizes() {
+        updateGephiGraph([cn: [filter: [nodeAttribute: [attribute: "visited", value: 1]],
+                               attributes: [size: 1, r: vizDefaultRGBColor[0], g: vizDefaultRGBColor[1], b: vizDefaultRGBColor[2]]]])
+        updateGephiGraph([ce: [filter: [edgeAttribute: [attribute: "visited", value: 1]],
+                               attributes: [size: 1, r: vizDefaultRGBColor[0], g: vizDefaultRGBColor[1], b: vizDefaultRGBColor[2]]]])
+    }
+
     def getFromGephiGraph(def Map queryArgs) {
         def http = new HTTPBuilder("http://$host:$port/")
         def resp = http.get(path: "/$workspace", query: queryArgs).getText()
@@ -310,4 +369,59 @@ class GephiRemoteAcceptor implements RemoteAcceptor {
         def http = new HTTPBuilder("http://$host:$port/")
         http.post(path: "/$workspace", requestContentType: JSON, body: postBody, query: [format: "JSON", operation: "updateGraph"])
     }
+
+    @Override
+    public String toString() {
+        return "Gephi - [$workspace]"
+    }
+
+    private void parseVizStepDelay(String arg) {
+        try {
+            vizStepDelay = Long.parseLong(arg)
+        } catch (Exception ignored) {
+            throw new RemoteException("The stepDelay must be a long value")
+        }
+    }
+
+    private void parseVizStartRGBColor(String arg) {
+        try {
+            vizStartRGBColor = arg[1..-2].tokenize(',')*.toFloat()
+            assert (vizStartRGBColor.length == 3)
+        } catch (Exception ignored) {
+            throw new RemoteException("The vizStartRGBColor must be an array of 3 float values, e.g. [0.0,1.0,0.5]")
+        }
+    }
+
+    private void parseVizColorToFade(String arg) {
+        try {
+            vizColorToFade = arg.charAt(0).toLowerCase();
+            assert (vizColorToFade == 'r' || vizColorToFade == 'g' || vizColorToFade == 'b')
+        } catch (Exception ignored) {
+            throw new RemoteException("The vizColorToFade must be one character value among: r, g, b, R, G, B")
+        }
+    }
+
+    private void parseVizColorFadeRate(String arg) {
+        try {
+            vizColorFadeRate = Float.parseFloat(arg)
+        } catch (Exception ignored) {
+            throw new RemoteException("The colorFadeRate must be a float value")
+        }
+    }
+
+    private void parseVizSizeDecrementRate(String arg) {
+        try {
+            vizSizeDecrementRate = Float.parseFloat(arg)
+        } catch (Exception ignored) {
+            throw new RemoteException("The sizeDecrementRate must be a float value")
+        }
+    }
+
+    private void parseVizStartSize(String arg) {
+        try {
+            vizStartSize = Float.parseFloat(arg)
+        } catch (Exception ignored) {
+            throw new RemoteException("The startSize must be a float value")
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiTraversalVisualizationStrategy.groovy
----------------------------------------------------------------------
diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiTraversalVisualizationStrategy.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiTraversalVisualizationStrategy.groovy
new file mode 100644
index 0000000..661d2ff
--- /dev/null
+++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/GephiTraversalVisualizationStrategy.groovy
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.tinkerpop.gremlin.console.plugin
+
+import groovy.transform.CompileStatic
+import org.apache.tinkerpop.gremlin.process.traversal.Step
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeOtherVertexStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.LambdaSideEffectStep
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.NoOpBarrierStep
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper
+import org.apache.tinkerpop.gremlin.structure.Vertex
+
+import java.util.stream.Collectors
+
+/**
+ * A strategy that works in conjuction with the {@link GephiRemoteAcceptor} to automatically inject visualization
+ * steps after "vertex" steps to show the vertices traversed for a step.  If the traversal was evaluated in the
+ * console normally then the visualization strategy will not be applied.  It must be {@code :submit} to the
+ * console for the strategy to be applied.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@CompileStatic
+class GephiTraversalVisualizationStrategy extends AbstractTraversalStrategy<TraversalStrategy.FinalizationStrategy>
+        implements TraversalStrategy.FinalizationStrategy {
+
+    private static final Set<Class<? extends TraversalStrategy.FinalizationStrategy>> POSTS = new HashSet<>();
+
+    static {
+        POSTS.add(ProfileStrategy.class);
+    }
+
+    private final GephiRemoteAcceptor acceptor
+
+    private final String sideEffectKey = "viz-" + UUID.randomUUID()
+
+    GephiTraversalVisualizationStrategy(final GephiRemoteAcceptor acceptor) {
+        this.acceptor = acceptor
+    }
+
+    @Override
+    void apply(final Traversal.Admin<?, ?> traversal) {
+        if (traversal.getEngine().isComputer())
+            return
+
+        // only apply these strategies if the traversal was :submit to the acceptor - otherwise process as usual
+        if (acceptor.traversalSubmittedForViz) {
+            final List<GraphStep> graphSteps = TraversalHelper.getStepsOfAssignableClass(GraphStep.class, traversal)
+            final List<VertexStep> vertexSteps = TraversalHelper.getStepsOfAssignableClass(VertexStep.class, traversal)
+
+            def List<Step> addAfter = new ArrayList<>()
+            addAfter.addAll(TraversalHelper.getStepsOfAssignableClass(EdgeOtherVertexStep.class, traversal))
+            addAfter.addAll(TraversalHelper.getStepsOfAssignableClass(EdgeVertexStep.class, traversal))
+            addAfter.addAll(vertexSteps.stream().filter { it.returnsVertex() }.collect(Collectors.toList()))
+            addAfter.addAll(graphSteps.stream().filter { it.returnsVertex() }.collect(Collectors.toList()))
+
+            // decay all vertices and visit each one to update their colors to the brightest
+            addAfter.each { Step s ->
+                TraversalHelper.insertAfterStep(new LambdaSideEffectStep(traversal, { Traverser traverser ->
+                    final BulkSet<Vertex> vertices = ((BulkSet<Vertex>) traverser.sideEffects(sideEffectKey))
+                    if (!vertices.isEmpty()) {
+                        acceptor.updateVisitedVertices()
+                        vertices.forEach { Vertex v, Long l -> acceptor.visitVertexInGephi(v) }
+                        vertices.clear()
+                        Thread.sleep(acceptor.vizStepDelay)
+                    }
+                }), s, traversal)
+                TraversalHelper.insertAfterStep(new AggregateStep(traversal, sideEffectKey), s, traversal)
+            }
+
+            // decay all vertices except those that made it through the filter - "this way you can watch
+            // the Gremlins dying" - said daniel kuppitz. can't do this easily with generic FilterStep as
+            // it creates odd behaviors when used with loop (extra decay that probably shouldn't be there.
+            // todo: can this be better? maybe we shouldn't do this at all
+            TraversalHelper.getStepsOfAssignableClass(HasStep.class, traversal).each { HasStep s ->
+                TraversalHelper.insertAfterStep(new LambdaSideEffectStep(traversal, { Traverser traverser ->
+                    final BulkSet<Object> objects = ((BulkSet<Object>) traverser.sideEffects(sideEffectKey))
+                    if (!objects.isEmpty()) {
+                        final List<String> vertices = objects.findAll{ Object o -> o instanceof Vertex}
+                                .collect { Object o -> ((Vertex) o).id().toString() }
+                        acceptor.updateVisitedVertices(vertices)
+                        objects.clear()
+                        Thread.sleep(acceptor.vizStepDelay)
+                    }
+                }), s, traversal)
+                TraversalHelper.insertAfterStep(new AggregateStep(traversal, sideEffectKey), s, traversal)
+            }
+        }
+    }
+
+    @Override
+    public Set<Class<? extends TraversalStrategy.FinalizationStrategy>> applyPost() {
+        return POSTS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPluginScript.groovy
----------------------------------------------------------------------
diff --git a/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPluginScript.groovy b/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPluginScript.groovy
index 3727675..5f5e3c6 100644
--- a/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPluginScript.groovy
+++ b/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPluginScript.groovy
@@ -49,4 +49,4 @@ describeGraph = { Class<? extends org.apache.tinkerpop.gremlin.structure.Graph>
 "the implementation itself.  Compliant implementations will faithfully and ${lf}" +
 "honestly supply these Annotations to provide the most accurate depiction of ${lf}" +
 "their support."
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiRemoteAcceptorIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiRemoteAcceptorIntegrateTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiRemoteAcceptorIntegrateTest.java
index 247fae7..79a7997 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiRemoteAcceptorIntegrateTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiRemoteAcceptorIntegrateTest.java
@@ -23,6 +23,8 @@ import org.apache.commons.io.input.NullInputStream;
 import org.apache.tinkerpop.gremlin.console.GremlinGroovysh;
 import org.apache.tinkerpop.gremlin.console.plugin.GephiRemoteAcceptor;
 import org.apache.tinkerpop.gremlin.groovy.plugin.RemoteException;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.codehaus.groovy.tools.shell.Groovysh;
 import org.codehaus.groovy.tools.shell.IO;
 import org.junit.Before;
@@ -37,13 +39,14 @@ import java.net.ServerSocket;
 import java.util.Arrays;
 import java.util.Collections;
 
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
 import static com.github.tomakehurst.wiremock.client.WireMock.get;
 import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
 import static com.github.tomakehurst.wiremock.client.WireMock.post;
 import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
 import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
 import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
 import static org.hamcrest.CoreMatchers.startsWith;
 import static org.junit.Assert.assertThat;
@@ -57,7 +60,7 @@ public class GephiRemoteAcceptorIntegrateTest {
 
     private GephiRemoteAcceptor acceptor;
 
-    private final InputStream inputStream  = new NullInputStream(0);
+    private final InputStream inputStream = new NullInputStream(0);
     private final OutputStream outputStream = new ByteArrayOutputStream();
     private final OutputStream errorStream = new ByteArrayOutputStream();
     private final IO io = new IO(inputStream, outputStream, errorStream);
@@ -65,6 +68,11 @@ public class GephiRemoteAcceptorIntegrateTest {
     @Rule
     public WireMockRule wireMockRule = new WireMockRule(port);
 
+    static {
+        final Graph graph = TinkerFactory.createModern();
+        groovysh.getInterp().getContext().setProperty("graph", graph);
+    }
+
     @Before
     public void before() throws Exception {
         acceptor = new GephiRemoteAcceptor(groovysh, io);
@@ -91,24 +99,101 @@ public class GephiRemoteAcceptorIntegrateTest {
 
         acceptor.submit(Arrays.asList("g = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph.open();g.addVertex();g"));
 
-        wireMockRule.verify(2, postRequestedFor(urlPathEqualTo("/workspace0")));
+        wireMockRule.verify(4, postRequestedFor(urlPathEqualTo("/workspace0")));
         wireMockRule.verify(1, getRequestedFor(urlPathEqualTo("/workspace0")));
     }
 
     @Test
-    public void shouldSubmitTraversal() throws RemoteException {
+    public void shouldSubmitPath() throws RemoteException {
+        stubFor(post(urlPathEqualTo("/workspace0"))
+                .withQueryParam("format", equalTo("JSON"))
+                .withQueryParam("operation", equalTo("updateGraph"))
+                .willReturn(aResponse()
+                        .withStatus(200)));
+
+        acceptor.submit(Arrays.asList(
+                "g = graph.traversal();g.V(1).repeat(org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__().both().dedup()).until(org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__().hasId(3)).path().next()"));
+
+        wireMockRule.verify(5, postRequestedFor(urlPathEqualTo("/workspace0")));
+    }
+
+    @Test
+    public void shouldSubmitMultiplePaths() throws RemoteException {
+        stubFor(post(urlPathEqualTo("/workspace0"))
+                .withQueryParam("format", equalTo("JSON"))
+                .withQueryParam("operation", equalTo("updateGraph"))
+                .willReturn(aResponse()
+                        .withStatus(200)));
+
+        acceptor.submit(Arrays.asList(
+                "g = graph.traversal();g.V(1).repeat(org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__().both().dedup()).until(org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__().hasId(3)).path().toList()"));
+
+        wireMockRule.verify(5, postRequestedFor(urlPathEqualTo("/workspace0")));
+    }
+
+    @Test
+    public void shouldSubmitTraversalAfterConfigWithDefaultG() throws RemoteException {
+        stubFor(post(urlPathEqualTo("/workspace0"))
+                .withQueryParam("format", equalTo("JSON"))
+                .withQueryParam("operation", equalTo("updateGraph"))
+                .willReturn(aResponse()
+                        .withStatus(200)));
+
+        acceptor.configure(Arrays.asList("visualTraversal", "graph"));
+
+        // call iterate() as groovysh isn't rigged to auto-iterate
+        acceptor.submit(Arrays.asList(
+                "vg.V(2).in('knows').out('knows').has('age',org.apache.tinkerpop.gremlin.process.traversal.P.gt(30)).outE('created').has('weight',org.apache.tinkerpop.gremlin.process.traversal.P.gt(0.5d)).inV().iterate()"));
+
+        wireMockRule.verify(18, postRequestedFor(urlPathEqualTo("/workspace0")));
+    }
+
+    @Test
+    public void shouldSubmitTraversalAfterConfigWithDefinedG() throws RemoteException {
+        stubFor(post(urlPathEqualTo("/workspace0"))
+                .withQueryParam("format", equalTo("JSON"))
+                .withQueryParam("operation", equalTo("updateGraph"))
+                .willReturn(aResponse()
+                        .withStatus(200)));
+
+        acceptor.configure(Arrays.asList("visualTraversal", "graph", "x"));
+
+        // call iterate() as groovysh isn't rigged to auto-iterate
+        acceptor.submit(Arrays.asList(
+                "x.V(2).in('knows').out('knows').has('age',org.apache.tinkerpop.gremlin.process.traversal.P.gt(30)).outE('created').has('weight',org.apache.tinkerpop.gremlin.process.traversal.P.gt(0.5d)).inV().iterate()"));
+
+        wireMockRule.verify(18, postRequestedFor(urlPathEqualTo("/workspace0")));
+    }
+
+    @Test
+    public void shouldSubmitTraversalOverRepeat() throws RemoteException {
+        stubFor(post(urlPathEqualTo("/workspace0"))
+                .withQueryParam("format", equalTo("JSON"))
+                .withQueryParam("operation", equalTo("updateGraph"))
+                .willReturn(aResponse()
+                        .withStatus(200)));
+
+        acceptor.configure(Arrays.asList("visualTraversal", "graph"));
+
+        // call iterate() as groovysh isn't rigged to auto-iterate
+        acceptor.submit(Arrays.asList(
+                "vg.V(1).repeat(org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__().out()).times(2).iterate()"));
+
+        wireMockRule.verify(13, postRequestedFor(urlPathEqualTo("/workspace0")));
+    }
+
+    @Test
+    public void shouldClearGraph() throws RemoteException {
         stubFor(post(urlPathEqualTo("/workspace0"))
                 .withQueryParam("format", equalTo("JSON"))
                 .withQueryParam("operation", equalTo("updateGraph"))
+                .withRequestBody(equalToJson("{\"dn\":{\"filter\":\"ALL\"}}"))
                 .willReturn(aResponse()
                         .withStatus(200)));
 
-        acceptor.submit(Arrays.asList("g = org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory.createModern().traversal();" +
-                "traversal = g.V(2).store('1').in('knows').store('2').out('knows').has('age',org.apache.tinkerpop.gremlin.process.traversal.P.gt(30)).store('3').outE('created').has('weight',org.apache.tinkerpop.gremlin.process.traversal.P.gt(0.5d)).inV().store('4');" +
-                "traversal.iterate();" +
-                "traversal"));
+        acceptor.submit(Arrays.asList("clear"));
 
-        wireMockRule.verify(10, postRequestedFor(urlPathEqualTo("/workspace0")));
+        wireMockRule.verify(1, postRequestedFor(urlPathEqualTo("/workspace0")));
     }
 
     private static int pickOpenPort() {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index f60f15a..f739355 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -20,7 +20,7 @@ limitations under the License.
     <parent>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>tinkerpop</artifactId>
-        <version>3.0.1-SNAPSHOT</version>
+        <version>3.1.0-SNAPSHOT</version>
     </parent>
     <artifactId>gremlin-core</artifactId>
     <name>Apache TinkerPop :: Gremlin Core</name>

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Path.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Path.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Path.java
index f8fa67b..25e69bb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Path.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Path.java
@@ -21,12 +21,8 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.javatuples.Pair;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
@@ -37,7 +33,7 @@ import java.util.stream.Stream;
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public interface Path extends Cloneable {
+public interface Path extends Cloneable, Iterable<Object> {
 
     /**
      * Get the number of step in the path.
@@ -57,13 +53,13 @@ public interface Path extends Cloneable {
      */
     public Path extend(final Object object, final Set<String> labels);
 
-    public default Path extend(final Object object, final String... labels) {
-        final Path path = this.extend(object, Collections.emptySet());
-        for (final String label : labels) {
-            path.addLabel(label);
-        }
-        return path;
-    }
+    /**
+     * Add labels to the head of the path.
+     *
+     * @param labels the labels at the head of the path
+     * @return the path with added labels
+     */
+    public Path extend(final Set<String> labels);
 
     /**
      * Get the object associated with the particular label of the path.
@@ -107,7 +103,7 @@ public interface Path extends Cloneable {
      * @throws IllegalArgumentException if the path does not contain the label
      */
     public default <A> A get(final Pop pop, final String label) throws IllegalArgumentException {
-        if(Pop.all == pop) {
+        if (Pop.all == pop) {
             if (this.hasLabel(label)) {
                 final Object object = this.get(label);
                 if (object instanceof List)
@@ -148,13 +144,6 @@ public interface Path extends Cloneable {
     }
 
     /**
-     * Add label to the current head of the path.
-     *
-     * @param label the label to add to the head of the path
-     */
-    public void addLabel(final String label);
-
-    /**
      * An ordered list of the objects in the path.
      *
      * @return the objects of the path
@@ -189,8 +178,8 @@ public interface Path extends Cloneable {
         return true;
     }
 
-    public default void forEach(final Consumer<Object> consumer) {
-        this.objects().forEach(consumer);
+    public default Iterator<Object> iterator() {
+        return this.objects().iterator();
     }
 
     public default void forEach(final BiConsumer<Object, Set<String>> consumer) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
index bf56d31..e0a63b6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java
@@ -22,7 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Conjun
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.EngineDependentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.DedupBijectionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.MatchPredicateStrategy;
@@ -200,7 +200,7 @@ public interface TraversalStrategies extends Serializable, Cloneable {
                     ProfileStrategy.instance(),
                     IncidentToAdjacentStrategy.instance(),
                     AdjacentToIncidentStrategy.instance(),
-                    DedupBijectionStrategy.instance(),
+                    FilterRankingStrategy.instance(),
                     IdentityRemovalStrategy.instance(),
                     MatchPredicateStrategy.instance(),
                     RangeByIsCountStrategy.instance(),

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
index fc5d421..06925a8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 import org.apache.tinkerpop.gremlin.structure.util.Attachable;
 
 import java.io.Serializable;
+import java.util.Set;
 import java.util.function.Function;
 
 /**
@@ -180,6 +181,8 @@ public interface Traverser<T> extends Serializable, Comparable<Traverser<T>>, Cl
          */
         public Admin<T> split();
 
+        public void addLabels(final Set<String> labels);
+
         /**
          * Set the current object location of the traverser.
          *

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 008a46c..a643e48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -18,137 +18,22 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
-import org.apache.tinkerpop.gremlin.process.traversal.Step;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.ElementValueTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.FunctionTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.LoopTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.TokenTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.lambda.TrueTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.*;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.*;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ComparatorHolder;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.BranchStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.ChooseStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.UnionStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CoinStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ConjunctionStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CyclicPathStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.LambdaFilterStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NotStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.SampleGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.SimplePathStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TailGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TimeLimitStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TraversalFilterStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WherePredicateStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.CoalesceStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConstantStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.DedupLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeOtherVertexStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.IdStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LabelStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaFlatMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapKeysStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapValuesStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PathStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertiesStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyKeyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyValueStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.RangeLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SackStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SampleLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectOneStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SumGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SumLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.TailLocalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.TreeStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupCountSideEffectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupSideEffectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.LambdaSideEffectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackElementValueStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackObjectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectCapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StoreStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TraversalSideEffectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TreeSideEffectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ElementFunctionComparator;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ElementValueComparator;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.NoOpBarrierStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.TraversalComparator;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.process.traversal.step.branch.*;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.*;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.*;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.*;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.*;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Element;
-import org.apache.tinkerpop.gremlin.structure.Property;
-import org.apache.tinkerpop.gremlin.structure.PropertyType;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.*;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
+import java.util.*;
+import java.util.function.*;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -517,14 +402,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new SackStep<>(this.asAdmin()));
     }
 
+    public default GraphTraversal<S, Integer> loops() {
+        return this.asAdmin().addStep(new LoopsStep<>(this.asAdmin()));
+    }
+
     /**
      * Map the {@link Traverser} to a {@link Map} projection of sideEffect values, map values, and/or path values.
      *
-     * @param pop               if there are multiple objects referenced in the path, the {@link Pop} to use.
+     * @param pop             if there are multiple objects referenced in the path, the {@link Pop} to use.
      * @param selectKey1      the first key to project
      * @param selectKey2      the second key to project
      * @param otherSelectKeys the third+ keys to project
-     * @param <E2>              the type of the objects projected
+     * @param <E2>            the type of the objects projected
      * @return the traversal with an appended {@link SelectStep}.
      */
     public default <E2> GraphTraversal<S, Map<String, E2>> select(final Pop pop, final String selectKey1, final String selectKey2, String... otherSelectKeys) {
@@ -541,7 +430,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @param selectKey1      the first key to project
      * @param selectKey2      the second key to project
      * @param otherSelectKeys the third+ keys to project
-     * @param <E2>              the type of the objects projected
+     * @param <E2>            the type of the objects projected
      * @return the traversal with an appended {@link SelectStep}.
      */
     public default <E2> GraphTraversal<S, Map<String, E2>> select(final String selectKey1, final String selectKey2, String... otherSelectKeys) {
@@ -983,7 +872,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     public default GraphTraversal<S, E> times(final int maxLoops) {
-        return this.until(new LoopTraversal(maxLoops));
+        return this.until(new LoopTraversal<>(maxLoops));
     }
 
     public default <E2> GraphTraversal<S, E2> local(final Traversal<?, E2> localTraversal) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 3d49d7a..e2d9e80 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -18,28 +18,14 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
 
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.*;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Property;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.*;
 
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
+import java.util.function.*;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -301,6 +287,13 @@ public class __ {
     }
 
     /**
+     * @see {@link GraphTraversal#loops()}
+     */
+    public static <A> GraphTraversal<A, Integer> loops() {
+        return __.<A>start().loops();
+    }
+
+    /**
      * @see {@link GraphTraversal#select(Pop, String)}
      */
     public static <A, B> GraphTraversal<A, B> select(final Pop pop, final String selectKey) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/LoopTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/LoopTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/LoopTraversal.java
index 59321f2..9c37853 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/LoopTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/LoopTraversal.java
@@ -1,21 +1,24 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  The ASF licenses this file
+ *  * to you 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.
  *
- * 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.
  */
+
 package org.apache.tinkerpop.gremlin.process.traversal.lambda;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -51,4 +54,4 @@ public final class LoopTraversal<S, E> extends AbstractLambdaTraversal<S, E> {
     public int hashCode() {
         return this.getClass().hashCode() ^ Long.hashCode(this.maxLoops);
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java
index 1ad9f43..6724619 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java
@@ -38,9 +38,9 @@ public interface Scoping {
     public static enum Variable {START, END}
 
     public static final Set<TraverserRequirement> TYPICAL_LOCAL_REQUIREMENTS = EnumSet.of(TraverserRequirement.OBJECT, TraverserRequirement.SIDE_EFFECTS);
-    public static final Set<TraverserRequirement> TYPICAL_GLOBAL_REQUIREMENTS = EnumSet.of(TraverserRequirement.OBJECT, TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
+    public static final Set<TraverserRequirement> TYPICAL_GLOBAL_REQUIREMENTS = EnumSet.of(TraverserRequirement.OBJECT, TraverserRequirement.LABELED_PATH, TraverserRequirement.SIDE_EFFECTS);
     public static final TraverserRequirement[] TYPICAL_LOCAL_REQUIREMENTS_ARRAY = new TraverserRequirement[]{TraverserRequirement.OBJECT, TraverserRequirement.SIDE_EFFECTS};
-    public static final TraverserRequirement[] TYPICAL_GLOBAL_REQUIREMENTS_ARRAY = new TraverserRequirement[]{TraverserRequirement.OBJECT, TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS};
+    public static final TraverserRequirement[] TYPICAL_GLOBAL_REQUIREMENTS_ARRAY = new TraverserRequirement[]{TraverserRequirement.OBJECT, TraverserRequirement.LABELED_PATH, TraverserRequirement.SIDE_EFFECTS};
 
     public default <S> S getScopeValue(final Pop pop, final String key, final Traverser.Admin<?> traverser) throws IllegalArgumentException {
         if (traverser.getSideEffects().get(key).isPresent())

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
index eee95e7..2989096 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
@@ -116,6 +116,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
             branch.forEach(traversal -> {
                 final Traverser.Admin<E> split = (Traverser.Admin<E>) start.split();
                 split.setStepId(traversal.getStartStep().getId());
+                //split.addLabels(this.labels);
                 ends.add(split);
             });
         }
@@ -125,6 +126,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
                 anyBranch.forEach(traversal -> {
                     final Traverser.Admin<E> split = (Traverser.Admin<E>) start.split();
                     split.setStepId(traversal.getStartStep().getId());
+                    //split.addLabels(this.labels);
                     ends.add(split);
                 });
             }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
index 21d848a..f9e1df6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
@@ -28,7 +28,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -164,6 +169,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
         if (doUntil(start, true)) {
             start.resetLoops();
             start.setStepId(this.getNextStep().getId());
+            start.addLabels(this.labels);
             return IteratorUtils.of(start);
         } else {
             start.setStepId(this.repeatTraversal.getStartStep().getId());
@@ -253,6 +259,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
             if (doUntil(start, false)) {
                 start.resetLoops();
                 start.setStepId(RepeatStep.this.getNextStep().getId());
+                start.addLabels(RepeatStep.this.labels);
                 return IteratorUtils.of(start);
             } else {
                 start.setStepId(RepeatStep.this.getId());

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java
index 5dc8510..0dfbe5f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java
@@ -105,7 +105,7 @@ public final class DedupGlobalStep<S> extends FilterStep<S> implements Traversal
 
     @Override
     public Set<TraverserRequirement> getRequirements() {
-        return this.dedupLabels == null ? this.getSelfAndChildRequirements(TraverserRequirement.BULK) : this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.BULK);
+        return this.dedupLabels == null ? this.getSelfAndChildRequirements(TraverserRequirement.BULK) : this.getSelfAndChildRequirements(TraverserRequirement.LABELED_PATH, TraverserRequirement.BULK);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
index a1a5455..bd4ef03 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
@@ -31,24 +31,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.ConjunctionP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class WherePredicateStep<S> extends FilterStep<S> implements Scoping {
 
-    private static final Set<TraverserRequirement> LOCAL_REQUIREMENTS = EnumSet.of(TraverserRequirement.OBJECT, TraverserRequirement.SIDE_EFFECTS);
-    private static final Set<TraverserRequirement> GLOBAL_REQUIREMENTS = EnumSet.of(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
-
     protected String startKey;
     protected List<String> selectKeys;
     protected P<Object> predicate;

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
new file mode 100644
index 0000000..2db9ab9
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+public final class LoopsStep<S> extends MapStep<S, Integer> {
+
+    public LoopsStep(final Traversal.Admin traversal) {
+        super(traversal);
+    }
+
+    @Override
+    protected Integer map(final Traverser.Admin<S> traverser) {
+        return traverser.loops();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapKeysStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapKeysStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapKeysStep.java
index 8aea53d..c8e722b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapKeysStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapKeysStep.java
@@ -23,21 +23,29 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.util.iterator.EmptyIterator;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MapKeysStep<S> extends FlatMapStep<Map<S, ?>, S> {
+public final class MapKeysStep<S, E> extends FlatMapStep<S, E> {
 
     public MapKeysStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
-    protected Iterator<S> flatMap(final Traverser.Admin<Map<S, ?>> traverser) {
-        return traverser.get().keySet().iterator();
+    protected Iterator<E> flatMap(final Traverser.Admin<S> traverser) {
+        final S s = traverser.get();
+        if (s instanceof Map)
+            return ((Map) s).keySet().iterator();
+        if (s instanceof Map.Entry)
+            return Collections.singleton((E) ((Map.Entry) s).getKey()).iterator();
+        return EmptyIterator.instance();
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapValuesStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapValuesStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapValuesStep.java
index fe41d15..10e35e2 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapValuesStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapValuesStep.java
@@ -23,21 +23,29 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.util.iterator.EmptyIterator;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MapValuesStep<S> extends FlatMapStep<Map<?, S>, S> {
+public final class MapValuesStep<S, E> extends FlatMapStep<S, E> {
 
     public MapValuesStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
-    protected Iterator<S> flatMap(final Traverser.Admin<Map<?, S>> traverser) {
-        return traverser.get().values().iterator();
+    protected Iterator<E> flatMap(final Traverser.Admin<S> traverser) {
+        final S s = traverser.get();
+        if (s instanceof Map)
+            return ((Map) s).values().iterator();
+        if (s instanceof Map.Entry)
+            return Collections.singleton((E) ((Map.Entry) s).getValue()).iterator();
+        return EmptyIterator.instance();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/ae644951/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
index ae1a264..dcb2078 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -312,8 +312,8 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 traverser = this.starts.next();
                 final Path path = traverser.path();
                 if (!this.matchStartLabels.stream().filter(path::hasLabel).findAny().isPresent())
-                    path.addLabel(this.computedStartLabel); // if the traverser doesn't have a legal start, then provide it the pre-computed one
-                path.addLabel(this.getId()); // so the traverser never returns to this branch ever again
+                    traverser.addLabels(Collections.singleton(this.computedStartLabel)); // if the traverser doesn't have a legal start, then provide it the pre-computed one
+                traverser.addLabels(Collections.singleton(this.getId())); // so the traverser never returns to this branch ever again
             }
             ///
             if (!this.isDuplicate(traverser)) {
@@ -337,13 +337,14 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
             final Traverser.Admin traverser = this.starts.next();
             final Path path = traverser.path();
             if (!this.matchStartLabels.stream().filter(path::hasLabel).findAny().isPresent())
-                path.addLabel(this.computedStartLabel); // if the traverser doesn't have a legal start, then provide it the pre-computed one
+                traverser.addLabels(Collections.singleton(this.computedStartLabel)); // if the traverser doesn't have a legal start, then provide it the pre-computed one
             if (!path.hasLabel(this.getId()))
-                path.addLabel(this.getId()); // so the traverser never returns to this branch ever again
+                traverser.addLabels(Collections.singleton(this.getId())); // so the traverser never returns to this branch ever again
             ///
             if (!this.isDuplicate(traverser)) {
                 if (hasMatched(this.conjunction, traverser)) {
                     traverser.setStepId(this.getNextStep().getId());
+                    traverser.addLabels(this.labels);
                     return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
                 }
                 if (this.conjunction == ConjunctionStep.Conjunction.AND) {
@@ -374,7 +375,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
     @Override
     public Set<TraverserRequirement> getRequirements() {
-        return this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
+        return this.getSelfAndChildRequirements(TraverserRequirement.LABELED_PATH, TraverserRequirement.SIDE_EFFECTS);
     }
 
     //////////////////////////////
@@ -392,7 +393,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
         @Override
         protected Traverser<Object> processNextStart() throws NoSuchElementException {
             final Traverser.Admin<Object> traverser = this.starts.next();
-            traverser.path().addLabel(this.getId());
+            traverser.addLabels(Collections.singleton(this.getId()));
             ((MatchStep<?, ?>) this.getTraversal().getParent()).getMatchAlgorithm().recordStart(traverser, this.getTraversal());
             // TODO: sideEffect check?
             return null == this.selectKey ? traverser : traverser.split(traverser.path().get(Pop.last, this.selectKey), this);
@@ -421,8 +422,8 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 this.scopeKeys = new HashSet<>();
                 if (null != this.selectKey)
                     this.scopeKeys.add(this.selectKey);
-                if (this.getNextStep() instanceof Scoping)
-                    this.scopeKeys.addAll(((Scoping) this.getNextStep()).getScopeKeys());
+                if (this.getNextStep() instanceof WhereTraversalStep || this.getNextStep() instanceof WherePredicateStep)
+                   this.scopeKeys.addAll(((Scoping) this.getNextStep()).getScopeKeys());
                 this.scopeKeys = Collections.unmodifiableSet(this.scopeKeys);
             }
             return this.scopeKeys;
@@ -444,7 +445,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 final Traverser.Admin traverser = this.starts.next();
                 // no end label
                 if (null == this.matchKey) {
-                    if (this.traverserStepIdSetByChild)
+                    if (this.traverserStepIdAndLabelsSetByChild)
                         traverser.setStepId(((MatchStep<?, ?>) this.getTraversal().getParent()).getId());
                     ((MatchStep<?, ?>) this.getTraversal().getParent()).getMatchAlgorithm().recordEnd(traverser, this.getTraversal());
                     return traverser;
@@ -453,9 +454,9 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 // path check
                 final Path path = traverser.path();
                 if (!path.hasLabel(this.matchKey) || traverser.get().equals(path.get(Pop.last, this.matchKey))) {
-                    if (this.traverserStepIdSetByChild)
+                    if (this.traverserStepIdAndLabelsSetByChild)
                         traverser.setStepId(((MatchStep<?, ?>) this.getTraversal().getParent()).getId());
-                    traverser.path().addLabel(this.matchKey);
+                    traverser.addLabels(Collections.singleton(this.matchKey));
                     ((MatchStep<?, ?>) this.getTraversal().getParent()).getMatchAlgorithm().recordEnd(traverser, this.getTraversal());
                     return traverser;
                 }